感觉自己数据结构水平越来越菜了。。。

题目链接

这个东西我想不出什么靠谱的做法,但是发现如果没有修改,用kd树很容易乱搞。在每个节点上维护框住所有点的矩形,如果查询的直线和这个矩形有交就往下做(这个kd树甚至都不能按坐标划分,但它跑得飞快)

然后修改和可持久化怎么做呢?我们考虑用类似treap的结构维护这棵kd树,然后修改就变成一个log的了。但是查询还是O(玄学)的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;

namespace fastio {
void read(int &x) {
x = 0;
bool sig = 0; char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') {
sig = 1; c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
if (sig) x = -x;
}

void read(ll &x) {
x = 0;
bool sig = 0; char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') {
sig = 1; c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
if (sig) x = -x;
}

void read(char &c) {
c = getchar();
while (!isgraph(c)) c = getchar();
}

void read(char *s) {
scanf("%s", s);
}

void read(double &x) {
x = 0;
bool sig = 0; char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') {
sig = 1; c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
if (c == '.') {
c = getchar(); double w = 0.1;
while (c >= '0' && c <= '9') {
x += (c - '0') * w;
c = getchar(); w /= 10;
}
}
if (sig) x = -x;
}

void read(ld &x) {
x = 0;
bool sig = 0; char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') {
sig = 1; c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
if (c == '.') {
c = getchar(); double w = 0.1;
while (c >= '0' && c <= '9') {
x += (c - '0') * w;
c = getchar(); w /= 10;
}
}
if (sig) x = -x;
}

void read() {}

template <typename type, typename... types>
void read(type &x, types&... y) {
read(x);
read(y...);
}
}
using namespace fastio;

const int maxn = 200000, inf = 0x3f3f3f3f;
int n, m, c;

struct vec {
int x, y;
}a[maxn + 10];
vec operator + (const vec &a, const vec &b) {
return (vec){a.x + b.x, a.y + b.y};
}
vec operator - (const vec &a, const vec &b) {
return (vec){a.x - b.x, a.y - b.y};
}
ll operator | (const vec &a, const vec &b) {
return 1ll * a.x * b.y - 1ll * a.y * b.x;
}
int sig(ll v) {
return v < 0 ? -1 : v > 0 ? 1 : 0;
}
struct line {
vec st, to;
};
bool cross(const line &a, const line &b) {
return sig(a.to | (b.st - a.st)) * sig(a.to | (b.st + b.to - a.st)) <= 0;
}

namespace kdtreap {
const int maxc = maxn * 50;

int mnx[maxc + 10], mxx[maxc + 10];
int mny[maxc + 10], mxy[maxc + 10];
int lc[maxc + 10], rc[maxc + 10], sz[maxc + 10], ndcnt;
vec val[maxc + 10], lv[maxc + 10], rv[maxc + 10];

int rnd(int x, int y) {
return rand() % (x + y) < x;
}

void init() {
mnx[0] = mny[0] = inf;
mxx[0] = mxy[0] = -inf;
}

void update(int p) {
sz[p] = sz[lc[p]] + sz[rc[p]] + 1;
mnx[p] = min(val[p].x, min(mnx[lc[p]], mnx[rc[p]]));
mxx[p] = max(val[p].x, max(mxx[lc[p]], mxx[rc[p]]));
mny[p] = min(val[p].y, min(mny[lc[p]], mny[rc[p]]));
mxy[p] = max(val[p].y, max(mxy[lc[p]], mxy[rc[p]]));
if (lc[p]) lv[p] = lv[lc[p]]; else lv[p] = val[p];
if (rc[p]) rv[p] = rv[rc[p]]; else rv[p] = val[p];
}

bool iscross(int p, const line &o) {
return cross(o, (line){(vec){mnx[p], mny[p]}, (vec){mxx[p] - mnx[p], 0}}) ||
cross(o, (line){(vec){mnx[p], mny[p]}, (vec){0, mxy[p] - mny[p]}}) ||
cross(o, (line){(vec){mxx[p], mxy[p]}, (vec){mnx[p] - mxx[p], 0}}) ||
cross(o, (line){(vec){mxx[p], mxy[p]}, (vec){0, mny[p] - mxy[p]}});
}

int copy(int p) {
++ndcnt;
mnx[ndcnt] = mnx[p]; mxx[ndcnt] = mxx[p];
mny[ndcnt] = mny[p]; mxy[ndcnt] = mxy[p];
lc[ndcnt] = lc[p]; rc[ndcnt] = rc[p]; sz[ndcnt] = sz[p];
val[ndcnt] = val[p]; lv[ndcnt] = lv[p]; rv[ndcnt] = rv[p];
return ndcnt;
}

int newnode(const vec &a) {
++ndcnt; val[ndcnt] = a;
update(ndcnt); return ndcnt;
}

pair<int, int> split(int p, int k) {
if (!p) return make_pair(0, 0);
p = copy(p); pair<int, int> r;
if (k <= sz[lc[p]]) {
r = split(lc[p], k);
lc[p] = r.second; update(r.second = p);
} else {
r = split(rc[p], k - sz[lc[p]] - 1);
rc[p] = r.first; update(r.first = p);
}
return r;
}

int merge(int x, int y) {
if (!x || !y) return x + y;
if (rnd(sz[x], sz[y])) {
x = copy(x); rc[x] = merge(rc[x], y);
update(x); return x;
} else {
y = copy(y); lc[y] = merge(x, lc[y]);
update(y); return y;
}
}

int build(int l, int r) {
if (l > r) return 0;
int mid = (l + r) >> 1;
val[mid] = a[mid];
lc[mid] = build(l, mid - 1);
rc[mid] = build(mid + 1, r);
update(mid); return mid;
}

int query(int p, const line &o) {
if (!p || !iscross(p, o)) return 0;
int ans = 0;
if (lc[p])
ans += cross(o, (line){val[p], rv[lc[p]] - val[p]}) + query(lc[p], o);
if (rc[p])
ans += cross(o, (line){val[p], lv[rc[p]] - val[p]}) + query(rc[p], o);
return ans;
}
}
int rt[maxn + 10], lst;

int main() {
read(n, m, c);
for (int i = 1; i <= n; ++i) read(a[i].x, a[i].y);
kdtreap::init(); rt[0] = kdtreap::build(1, n);
kdtreap::ndcnt = n;
for (int i = 1; i <= m; ++i) {
char ch; int t, k; vec st, to;
read(ch);
if (ch == 'H') {
read(t, st.x, st.y, to.x, to.y);
if (c) {
st.x ^= lst; st.y ^= lst;
to.x ^= lst; to.y ^= lst;
}
printf("%d\n", lst = kdtreap::query(rt[t], (line){st, to}));
rt[i] = rt[t];
} else {
read(t, k, st.x, st.y);
if (c) {
st.x ^= lst; st.y ^= lst;
}
pair<int, int> r = kdtreap::split(rt[t], k);
rt[i] = kdtreap::merge(r.first, kdtreap::merge(kdtreap::newnode(st), r.second));
}
}
}