大概就是把点分树建出来,维护每个点的信息和全局信息。
修改的时候考虑一个点对它点分树祖先的影响。
树上与距离有关的问题,考虑动态点分治。
例题:
洛谷P2056 捉迷藏
带修树上最远黑色点对。
这道题难点根本不在动态点分治,完全在于堆(们)好吧!!!我被这三种堆虐的死去活来,然后又T飞...换了O(1)lca才过。

1 struct PQ {
2 std::priority_queue<int> a, b;
3 inline void push(int x) {
4 a.push(x);
5 return;
6 }
7 inline void update() {
8 while(a.size() && b.size() && a.top() == b.top()) {
9 a.pop();
10 b.pop();
11 }
12 return;
13 }
14 inline void pop() {
15 update();
16 if(a.size()) {
17 a.pop();
18 }
19 return;
20 }
21 inline void del(int x) {
22 b.push(x);
23 return;
24 }
25 inline int top() {
26 update();
27 return a.size() ? a.top() : -INF;
28 }
29 inline int size() {
30 return std::max((int)(a.size() - b.size()), 0);
31 }
32 inline bool empty() {
33 return a.size() <= b.size();
34 }
35 };
Ql[x]维护当前节点管辖的连通块到FA[x]的距离。
Qs[x]维护每个子节点Ql的最大值(包括他自己的距离)。
还有个全局的ans维护所有Qs的前两大之和(答案)。

1 // luogu-judger-enable-o2
2 #include <cstdio>
3 #include <algorithm>
4 #include <queue>
5
6 const int N = 200010, INF = 0x3f3f3f3f;
7
8 inline void read(int &x) {
9 x = 0;
10 char c = getchar();
11 while(c < '0' || c > '9') {
12 c = getchar();
13 }
14 while(c >= '0' && c <= '9') {
15 x = (x << 3) + (x << 1) + c - 48;
16 c = getchar();
17 }
18 return;
19 }
20
21 struct Edge {
22 int nex, v;
23 }edge[N << 1], EDGE[N << 1]; int tp, TP;
24
25 struct PQ {
26 std::priority_queue<int> a, b;
27 inline void push(int x) {
28 a.push(x);
29 return;
30 }
31 inline void update() {
32 while(a.size() && b.size() && a.top() == b.top()) {
33 a.pop();
34 b.pop();
35 }
36 return;
37 }
38 inline void pop() {
39 update();
40 if(a.size()) {
41 a.pop();
42 }
43 return;
44 }
45 inline void del(int x) {
46 b.push(x);
47 return;
48 }
49 inline int top() {
50 update();
51 return a.size() ? a.top() : -INF;
52 }
53 inline int size() {
54 return std::max((int)(a.size() - b.size()), 0);
55 }
56 inline bool empty() {
57 return a.size() <= b.size();
58 }
59 }Ql[N], Qs[N], ans;
60
61 int e[N], dist[N], n, root, _n, small, siz[N], fr[N], E[N], FA[N], d[N], Cnt, pw[N << 1], fa[N];
62 int pos[N << 1], num, ST[N << 1][20];
63 bool del[N], col[N];
64
65 inline void add(int x, int y) {
66 tp++;
67 edge[tp].v = y;
68 edge[tp].nex = e[x];
69 e[x] = tp;
70 return;
71 }
72
73 inline void ADD(int x, int y) {
74 TP++;
75 EDGE[TP].v = y;
76 EDGE[TP].nex = E[x];
77 E[x] = TP;
78 return;
79 }
80
81 inline int lca(int x, int y) {
82 x = pos[x];
83 y = pos[y];
84 if(x > y) std::swap(x, y);
85 int t = pw[y - x + 1];
86 if(dist[ST[x][t]] < dist[ST[y - (1 << t) + 1][t]]) {
87 return ST[x][t];
88 }
89 else
90 return ST[y - (1 << t) + 1][t];
91 }
92
93 inline int dis(int x, int y) {
94 return dist[x] + dist[y] - dist[lca(x, y)] * 2;
95 }
96
97 inline void prework() {
98 for(int i = 2; i <= num; i++) {
99 pw[i] = pw[i >> 1] + 1;
100 }
101 for(int j = 1; j <= pw[num]; j++) {
102 for(int i = 1; i <= num; i++) {
103 if(dist[ST[i][j - 1]] < dist[ST[i + (1 << (j - 1))][j - 1]])
104 ST[i][j] = ST[i][j - 1];
105 else
106 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
107 }
108 }
109 return;
110 }
111
112 void DFS_0(int x, int father) {
113 fa[x] = father;
114 dist[x] = dist[father] + 1;
115 pos[x] = ++num;
116 ST[num][0] = x;
117 for(int i = e[x]; i; i = edge[i].nex) {
118 int y = edge[i].v;
119 if(y == father) continue;
120 DFS_0(y, x);
121 ST[++num][0] = x;
122 }
123 return;
124 }
125
126 void get_root(int x, int father) {
127 int large = 0;
128 siz[x] = 1;
129 for(int i = e[x]; i; i = edge[i].nex) {
130 int y = edge[i].v;
131 if(del[y] || y == father) {
132 continue;
133 }
134 get_root(y, x);
135 siz[x] += siz[y];
136 large = std::max(large, siz[y]);
137 }
138 large = std::max(large, _n - siz[x]);
139 if(small > large) {
140 small = large;
141 root = x;
142 }
143 return;
144 }
145
146 void DFS_1(int x, int father, int rt) {
147 Ql[rt].push(d[x]);
148 //printf("Ql %d push %d %d \n", rt, x, d[x]);
149 siz[x] = 1;
150 d[x] = d[father] + 1;
151 for(int i = e[x]; i; i = edge[i].nex) {
152 int y = edge[i].v;
153 if(del[y] || y == father) continue;
154 DFS_1(y, x, rt);
155 siz[x] += siz[y];
156 }
157 return;
158 }
159
160 void poi_div(int x, int father) {
161 small = INF;
162 get_root(x, 0);
163 x = root;
164 FA[x] = father;
165 if(father) ADD(father, x);
166 Ql[x].push(d[x]);
167 //printf("Ql %d push %d %d \n", x, x, d[x]);
168
169 d[x] = 0;
170 for(int i = e[x]; i; i = edge[i].nex) {
171 int y = edge[i].v;
172 if(del[y]) continue;
173 DFS_1(y, x, x);
174 }
175
176 del[x] = 1;
177 for(int i = e[x]; i; i = edge[i].nex) {
178 int y = edge[i].v;
179 if(del[y]) continue;
180 _n = siz[y];
181 poi_div(y, x);
182 }
183 return;
184 }
185
186 void DFS_2(int x) {
187 //printf("DFS2 : x = %d \n", x);
188 for(int i = E[x]; i; i = EDGE[i].nex) {
189 int y = EDGE[i].v;
190 DFS_2(y);
191 int temp = Ql[y].top();
192 Qs[x].push(temp);
193 //printf("x = %d y = %d push %d %d \n", x, y, temp.x, temp.d);
194 }
195 Qs[x].push(0);
196 /// get Answer
197 int temp = Qs[x].top();
198 Qs[x].pop();
199 if(Qs[x].size()) {
200 int Ans = Qs[x].top() + temp;
201 ans.push(Ans);
202 }
203 Qs[x].push(temp);
204 return;
205 }
206
207 inline int getAns() {
208 if(Cnt == 0) return -1;
209 if(Cnt == 1) return 0;
210 return ans.top();
211 }
212
213 char str[3];
214
215 inline int cal_ans(int x) {
216 int t = Qs[x].top();
217 Qs[x].pop();
218 int ans = t + Qs[x].top();
219 Qs[x].push(t);
220 return ans;
221 }
222
223 inline void change(int x) {
224 if(col[x] == 0) Cnt--;
225 else Cnt++;
226 bool f = col[x];
227 col[x] ^= 1;
228
229 if(f) {
230 ans.del(cal_ans(x));
231 Qs[x].push(0);
232 ans.push(cal_ans(x));
233 }
234 else {
235 ans.del(cal_ans(x));
236 Qs[x].del(0);
237 ans.push(cal_ans(x));
238 }
239
240 int first_x = x;
241 while(FA[x]) {
242 int F = FA[x];
243 int temp = Ql[x].top();
244 if(f)
245 Ql[x].push(dis(F, first_x));
246 else
247 Ql[x].del(dis(F, first_x));
248 if(temp != Ql[x].top()) {
249 int temp_ans = cal_ans(F);
250 Qs[F].del(temp);
251 Qs[F].push(Ql[x].top());
252 int now_ans = cal_ans(F);
253 if(now_ans != temp_ans) {
254 ans.del(temp_ans);
255 ans.push(now_ans);
256 }
257 }
258 x = F;
259 }
260 return;
261 }
262
263 int main() {
264 read(n);
265 for(int i = 1, x, y; i < n; i++) {
266 read(x); read(y);
267 add(x, y); add(y, x);
268 }
269
270 DFS_0(1, 0);
271 prework();
272 Cnt = _n = n;
273 poi_div(1, 0);
274 for(int i = 1; i <= n; i++) {
275 if(!FA[i]) root = i;
276 //printf("FA %d = %d \n", i, FA[i]);
277 }
278 DFS_2(root);
279
280
281 int q;
282 read(q);
283 for(int i = 1, x; i <= q; i++) {
284 scanf("%s", str);
285 if(str[0] == 'G') {
286 printf("%d\n", getAns());
287 }
288 else {
289 read(x);
290 change(x);
291 }
292 }
293
294 return 0;
295 }
感觉动态点分治主要是难在理清思路上......
洛谷P3345 幻想乡战略游戏
动态带权重心。
这TM又是个毒瘤题...昨天看题解脑袋全是糊的。代码错上天。今天自己YY出了解法终于写对了......
考虑随机选一个点,如何调整?如果有一个子树里面siz比总的一半要大,就过去。
然后我们利用点分树结构,去到那个子树的连通块内的重心。这样只要找logn次即可。
考虑如何判断:要查询以x为根的时候他的一个子节点的权值和,显然一个DFS序树状数组就没了。
这样就能够找到答案所在的点。那么如何统计答案呢?
正着来实在是奥妙重重,我完全搞不倒,所以考虑回溯时累加。
从y回溯到x之后,把x的点分子树中除了y子树的代价都加上。y子树内的之前统计了。
我们需要SIZ[x]表示x的点分子树内的总个数,dx[x]表示x的点分子树内全部到x的总距离。df[x]表示x的点分子树全部到FA[x]的总距离。
利用这三个数组可以把y子树挖掉然后计算其它的总代价。当然我们需要一个O(1)两点在原树间的距离。
修改就沿途修改这三个数组。
实现细节:ask的时候在点分树上面走。near[x]表示x的点分子树中,原树距离FA[x]最近的点。
顺便%一下本题的线段树二分解法,神奇。

1 #include <cstdio>
2 #include <algorithm>
3
4 typedef long long LL;
5 const int N = 100010, INF = 0x3f3f3f3f;
6
7 struct Edge {
8 int nex, v;
9 LL len;
10 }edge[N << 1], EDGE[N << 1]; int tp, TP;
11
12 int n, e[N], E[N], FA[N], ROOT, root, fa[N], near[N];
13 int num, pos[N], ST[N << 1][20], pw[N << 1], deep[N], siz[N], _n, small;
14 LL dist[N];
15 bool del[N];
16 LL dx[N], df[N], TOT, SIZ[N];
17
18 namespace ta {
19 int pos[N], siz[N], num;
20 LL ta[N];
21 inline void add(int x, LL v) {
22 for(int i = pos[x]; i <= n; i += i & (-i)) {
23 ta[i] += v;
24 }
25 return;
26 }
27 inline LL getSum(int x) {
28 LL ans = 0;
29 for(int i = x; i >= 1; i -= i & (-i)) {
30 ans += ta[i];
31 }
32 return ans;
33 }
34 inline LL ask(int x) {
35 return getSum(pos[x] + siz[x] - 1) - getSum(pos[x] - 1);
36 }
37 }
38
39 inline void add(int x, int y, LL z) {
40 tp++;
41 edge[tp].v = y;
42 edge[tp].len = z;
43 edge[tp].nex = e[x];
44 e[x] = tp;
45 return;
46 }
47
48 inline void ADD(int x, int y, LL z = 0) {
49 TP++;
50 EDGE[TP].v = y;
51 EDGE[TP].len = z;
52 EDGE[TP].nex = E[x];
53 E[x] = TP;
54 return;
55 }
56
57 void DFS_0(int x, int f) {
58 pos[x] = ++num;
59 ST[num][0] = x;
60 deep[x] = deep[f] + 1;
61 fa[x] = f;
62 ta::siz[x] = 1;
63 ta::pos[x] = ++ta::num;
64 for(int i = e[x]; i; i = edge[i].nex) {
65 int y = edge[i].v;
66 if(y == f) continue;
67 dist[y] = dist[x] + edge[i].len;
68 DFS_0(y, x);
69 ta::siz[x] += ta::siz[y];
70 ST[++num][0] = x;
71 }
72 return;
73 }
74
75 inline void prework() {
76 for(int i = 2; i <= num; i++) {
77 pw[i] = pw[i >> 1] + 1;
78 }
79 for(int j = 1; j <= pw[num]; j++) {
80 for(int i = 1; i + (1 << j) - 1 <= num; i++) {
81 if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
82 ST[i][j] = ST[i][j - 1];
83 else
84 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
85 }
86 }
87 return;
88 }
89
90 inline int lca(int x, int y) {
91 x = pos[x]; y = pos[y];
92 if(x > y) std::swap(x, y);
93 int t = pw[y - x + 1];
94 if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
95 return ST[x][t];
96 else
97 return ST[y - (1 << t) + 1][t];
98 }
99
100 inline LL dis(int x, int y) {
101 return dist[x] + dist[y] - 2 * dist[lca(x, y)];
102 }
103
104 void get_root(int x, int f) {
105 siz[x] = 1;
106 int large = 0;
107 for(int i = e[x]; i; i = edge[i].nex) {
108 int y = edge[i].v;
109 if(del[y] || y == f) {
110 continue;
111 }
112 get_root(y, x);
113 siz[x] += siz[y];
114 large = std::max(large, siz[y]);
115 }
116 large = std::max(large, _n - siz[x]);
117 if(small > large) {
118 small = large;
119 root = x;
120 }
121 return;
122 }
123
124 void DFS_1(int x, int f, int rt) {
125 siz[x] = 1;
126 for(int i = e[x]; i; i = edge[i].nex) {
127 int y = edge[i].v;
128 if(y == ROOT) {
129 near[rt] = x;
130 }
131 if(del[y] || y == f) continue;
132 DFS_1(y, x, rt);
133 siz[x] += siz[y];
134 }
135 return;
136 }
137
138 void poi_div(int x, int father) {
139 small = INF;
140 get_root(x, 0);
141 x = root;
142 FA[x] = father;
143 if(father) ADD(father, x);
144
145 ROOT = father;
146 for(int i = e[x]; i; i = edge[i].nex) {
147 int y = edge[i].v;
148 if(del[y]) continue;
149 DFS_1(y, x, x);
150 }
151
152 del[x] = 1;
153 for(int i = e[x]; i; i = edge[i].nex) {
154 int y = edge[i].v;
155 if(del[y]) continue;
156 _n = siz[y];
157 poi_div(y, x);
158 }
159
160 if(!near[x]) near[x] = x;
161 return;
162 }
163
164 inline void change(int x, LL v) {
165 TOT += v;
166 ta::add(x, v);
167 int first_x = x;
168 while(x) {
169 SIZ[x] += v;
170 if(FA[x]) {
171 df[x] += v * dis(first_x, FA[x]);
172 }
173 dx[x] += v * dis(first_x, x);
174 x = FA[x];
175 }
176 return;
177 }
178
179 inline LL getSIZ(int x, int f) {
180 if(fa[x] == f) return ta::ask(x);
181 else return TOT - ta::ask(f);
182 }
183
184 int ask(int x, LL &v) {
185 int ans = x;
186 for(int i = E[x]; i; i = EDGE[i].nex) {
187 int y = EDGE[i].v;
188 if(2 * getSIZ(near[y], x) > TOT) {
189 ans = y;
190 break;
191 }
192 }
193 if(ans == x) {
194 /// now is ans
195 v = dx[x];
196 return x;
197 }
198 else {
199 int p = ask(ans, v);
200 v += dx[x] - df[ans] + (SIZ[x] - SIZ[ans]) * dis(x, p);
201 return p;
202 }
203 }
204
205 int main() {
206
207 int q; LL z;
208 scanf("%d%d", &n, &q);
209 for(int i = 1, x, y; i < n; i++) {
210 scanf("%d%d%lld", &x, &y, &z);
211 add(x, y, z);
212 add(y, x, z);
213 }
214
215 DFS_0(1, 0);
216 prework();
217 _n = n;
218 poi_div(1, 0);
219
220 for(int i = 1; i <= n; i++) {
221 if(!FA[i]) {
222 root = i;
223 break;
224 }
225 }
226
227 LL v;
228 for(int i = 1, x; i <= q; i++) {
229 scanf("%d%lld", &x, &v);
230 /// val[x] += y;
231 change(x, v);
232 LL t;
233 ask(root, t);
234 printf("%lld\n", t);
235 }
236
237 return 0;
238 }
对拍真是个好东西...
BZOJ3730 震波
带修半径k内点权和。
这个比上面两个好想好写一点,当然写出来又错了一堆...注意不要把first_x写成x。对拍真好用。
点分树上每个点开一个数据结构维护点分子树内距离它深度为d的权值和。跟上一题一样,从下往上查,减去算重的答案即可。

1 #include <cstdio>
2 #include <algorithm>
3
4 const int N = 100010, INF = 0x3f3f3f3f, M = 20000010;
5
6 inline void read(int &x) {
7 x = 0;
8 char c = getchar();
9 while(c < '0' || c > '9') {
10 c = getchar();
11 }
12 while(c >= '0' && c <= '9') {
13 x = (x << 3) + (x << 1) + c - 48;
14 c = getchar();
15 }
16 return;
17 }
18
19 struct Edge {
20 int nex, v;
21 }edge[N << 1]; int tp;
22
23 int FA[N], e[N], siz[N], n, pos[N], num, ST[N << 1][20], pw[N << 1], deep[N], small, root, _n, d[N];
24 bool del[N];
25 int val[N];
26
27 namespace seg {
28 int tot, sum[M], ls[M], rs[M], rt[N << 1];
29 void add(int p, int v, int l, int r, int &o) {
30 if(!o) o = ++tot;
31 sum[o] += v;
32 if(l == r) {
33 return;
34 }
35 int mid = (l + r) >> 1;
36 if(p <= mid) add(p, v, l, mid, ls[o]);
37 else add(p, v, mid + 1, r, rs[o]);
38 return;
39 }
40 inline void insert(int id, int p, int v) {
41 add(p + 1, v, 1, n, rt[id]);
42 return;
43 }
44 int getSum(int L, int R, int l, int r, int o) {
45 if(!o) return 0;
46 if(L <= l && r <= R) return sum[o];
47 int mid = (l + r) >> 1, ans = 0;
48 if(L <= mid) ans += getSum(L, R, l, mid, ls[o]);
49 if(mid < R) ans += getSum(L, R, mid + 1, r, rs[o]);
50 return ans;
51 }
52 inline int ask(int id, int L, int R) {
53 if(L > R) return 0;
54 return getSum(L + 1, R + 1, 1, n, rt[id]);
55 }
56 }
57
58 inline void add(int x, int y) {
59 tp++;
60 edge[tp].v = y;
61 edge[tp].nex = e[x];
62 e[x] = tp;
63 return;
64 }
65
66 void DFS_0(int x, int f) {
67 pos[x] = ++num;
68 ST[num][0] = x;
69 deep[x] = deep[f] + 1;
70 for(int i = e[x]; i; i = edge[i].nex) {
71 int y = edge[i].v;
72 if(y == f) continue;
73 DFS_0(y, x);
74 ST[++num][0] = x;
75 }
76 return;
77 }
78
79 inline void prework() {
80 for(int i = 2; i <= num; i++) {
81 pw[i] = pw[i >> 1] + 1;
82 }
83 for(int j = 1; j <= pw[num]; j++) {
84 for(int i = 1; i + (1 << j) - 1 <= num; i++) {
85 if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
86 ST[i][j] = ST[i][j - 1];
87 else
88 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
89 }
90 }
91 return;
92 }
93
94 inline int lca(int x, int y) {
95 x = pos[x];
96 y = pos[y];
97 if(x > y) std::swap(x, y);
98 int t = pw[y - x + 1];
99 if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
100 return ST[x][t];
101 else
102 return ST[y - (1 << t) + 1][t];
103 }
104
105 inline int dis(int x, int y) {
106 return deep[x] + deep[y] - 2 * deep[lca(x, y)];
107 }
108
109 void get_root(int x, int f) {
110 siz[x] = 1;
111 int large = 0;
112 for(int i = e[x]; i; i = edge[i].nex) {
113 int y = edge[i].v;
114 if(y == f || del[y]) {
115 continue;
116 }
117 get_root(y, x);
118 siz[x] += siz[y];
119 large = std::max(large, siz[y]);
120 }
121 large = std::max(large, _n - siz[x]);
122 if(large < small) {
123 small = large;
124 root = x;
125 }
126 return;
127 }
128
129 void DFS_1(int x, int f, int rt) {
130 siz[x] = 1;
131 if(FA[rt]) {
132 seg::insert(rt + n, d[x], val[x]);
133 }
134 d[x] = d[f] + 1;
135 seg::insert(rt, d[x], val[x]);
136 //printf("insert %d %d %d \n", rt, d[x], val[x]);
137 for(int i = e[x]; i; i = edge[i].nex) {
138 int y = edge[i].v;
139 if(del[y] || y == f) {
140 continue;
141 }
142 DFS_1(y, x, rt);
143 siz[x] += siz[y];
144 }
145 return;
146 }
147
148 void poi_div(int x, int f) {
149 small = INF;
150 get_root(x, 0);
151 x = root;
152 FA[x] = f;
153
154 seg::insert(x, 0, val[x]);
155 if(f) {
156 seg::insert(x + n, d[x], val[x]);
157 }
158 d[x] = 0;
159 for(int i = e[x]; i; i = edge[i].nex) {
160 int y = edge[i].v;
161 if(del[y]) continue;
162 DFS_1(y, x, x);
163 }
164
165 del[x] = 1;
166 for(int i = e[x]; i; i = edge[i].nex) {
167 int y = edge[i].v;
168 if(del[y]) {
169 continue;
170 }
171 _n = siz[y];
172 poi_div(y, x);
173 }
174 return;
175 }
176
177 inline void change(int x, int v) {
178 /// val[x] = v
179 int first_x = x;
180 while(x) {
181 int t = dis(first_x, x);
182 seg::insert(x, t, v - val[first_x]);
183 if(FA[x]) {
184 seg::insert(x + n, dis(first_x, FA[x]), v - val[first_x]);
185 }
186 x = FA[x];
187 }
188 val[first_x] = v;
189 return;
190 }
191
192 inline int ask(int x, int k) {
193 int first_x = x, ans = 0;
194 while(x) {
195 ans += seg::ask(x, 0, k - dis(x, first_x));
196 //printf("ans += [%d %d] %d \n", 0, k - dis(x, first_x), seg::ask(x, 0, k - dis(x, first_x)));
197 if(FA[x]) {
198 ans -= seg::ask(x + n, 0, k - dis(FA[x], first_x));
199 //printf("ans -= [%d %d] %d \n", 0, k - dis(FA[x], first_x), seg::ask(x + n, 0, k - dis(FA[x], first_x)));
200 }
201 //printf("%d %d \n", x, ans);
202 x = FA[x];
203 }
204 return ans;
205 }
206
207 int main() {
208
209 int q;
210 read(n); read(q);
211 for(int i = 1; i <= n; i++) {
212 read(val[i]);
213 }
214 for(int i = 1, x, y; i < n; i++) {
215 read(x); read(y);
216 add(x, y); add(y, x);
217 }
218
219 DFS_0(1, 0);
220 prework();
221 _n = n;
222 poi_div(1, 0);
223
224 /*for(int i = 1; i <= n; i++) {
225 printf("FA %d = %d \n", i, FA[i]);
226 }
227 puts("");*/
228
229 int lastans = 0;
230 for(int i = 1, f, x, y; i <= q; i++) {
231 read(f); read(x); read(y);
232 x ^= lastans; y ^= lastans;
233 if(f == 0) { /// ask
234 lastans = ask(x, y);
235 printf("%d\n", lastans);
236 }
237 else { /// change
238 change(x, y);
239 }
240 }
241
242 return 0;
243 }
差0.06s就TLE还行。常数过大引起不适.jpg
BZOJ4372 烁烁的游戏
论刷题的作用.....不调1A点分树还行。
跟上面一题完全倒过来了...修改一个点半径k内的点,询问点权。
有个很妙的想法是点分树上每个点维护它的点分子树中原树距它为d的点的修改量。查询的时候一路跳上去。
去重的方法跟上面一样,再开个线段树维护x的点分子树中原树距离FA[x]为d的点的修改量。

1 #include <cstdio>
2 #include <algorithm>
3
4 const int N = 100010, INF = 0x3f3f3f3f, M = 20000010;
5
6 inline void read(int &x) {
7 x = 0;
8 char c = getchar();
9 bool f = 0;
10 while(c < '0' || c > '9') {
11 if(c == '-') {
12 f = 1;
13 }
14 c = getchar();
15 }
16 while(c >= '0' && c <= '9') {
17 x = (x << 3) + (x << 1) + c - 48;
18 c = getchar();
19 }
20 if(f) {
21 x = (~x) + 1;
22 }
23 return;
24 }
25
26 struct Edge {
27 int nex, v;
28 }edge[N << 1]; int tp;
29
30 int e[N], FA[N], n, num, ST[N << 1][20], pw[N << 1], deep[N], small, root, _n, siz[N], pos[N];
31 char str[3];
32 bool del[N];
33
34 inline void add(int x, int y) {
35 tp++;
36 edge[tp].v = y;
37 edge[tp].nex = e[x];
38 e[x] = tp;
39 return;
40 }
41
42 namespace seg {
43 int tot, tag[M], ls[M], rs[M], rt[N << 1];
44 inline void pushdown(int o) {
45 if(tag[o]) {
46 if(!ls[o]) ls[o] = ++tot;
47 if(!rs[o]) rs[o] = ++tot;
48 tag[ls[o]] += tag[o];
49 tag[rs[o]] += tag[o];
50 tag[o] = 0;
51 }
52 return;
53 }
54 void add(int L, int R, int v, int l, int r, int &o) {
55 if(!o) o = ++tot;
56 if(L <= l && r <= R) {
57 tag[o] += v;
58 return;
59 }
60 pushdown(o);
61 int mid = (l + r) >> 1;
62 if(L <= mid) {
63 add(L, R, v, l, mid, ls[o]);
64 }
65 if(mid < R) {
66 add(L, R, v, mid + 1, r, rs[o]);
67 }
68 return;
69 }
70 int getSum(int p, int l, int r, int o) {
71 if(!o) return 0;
72 if(l == r) {
73 return tag[o];
74 }
75 pushdown(o);
76 int mid = (l + r) >> 1;
77 if(p <= mid) {
78 return getSum(p, l, mid, ls[o]);
79 }
80 else {
81 return getSum(p, mid + 1, r, rs[o]);
82 }
83 }
84 inline void insert(int id, int L, int R, int v) {
85 add(L + 1, R + 1, v, 1, n, rt[id]);
86 return;
87 }
88 inline int ask(int id, int p) {
89 return getSum(p + 1, 1, n, rt[id]);
90 }
91 }
92
93 void DFS_0(int x, int f) {
94 pos[x] = ++num;
95 ST[num][0] = x;
96 deep[x] = deep[f] + 1;
97 for(int i = e[x]; i; i = edge[i].nex) {
98 int y = edge[i].v;
99 if(y == f) continue;
100 DFS_0(y, x);
101 ST[++num][0] = x;
102 }
103 return;
104 }
105
106 inline void prework() {
107 for(int i = 2; i <= num; i++) {
108 pw[i] = pw[i >> 1] + 1;
109 }
110 for(int j = 1; j <= pw[num]; j++) {
111 for(int i = 1; i + (1 << j) - 1 <= num; i++) {
112 if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
113 ST[i][j] = ST[i][j - 1];
114 else
115 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
116 }
117 }
118 return;
119 }
120
121 inline int lca(int x, int y) {
122 x = pos[x];
123 y = pos[y];
124 if(x > y) std::swap(x, y);
125 int t = pw[y - x + 1];
126 if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]])
127 return ST[x][t];
128 else
129 return ST[y - (1 << t) + 1][t];
130 }
131
132 inline int dis(int x, int y) {
133 return deep[x] + deep[y] - 2 * deep[lca(x, y)];
134 }
135
136 void get_root(int x, int f) {
137 siz[x] = 1;
138 int large = 0;
139 for(int i = e[x]; i; i = edge[i].nex) {
140 int y = edge[i].v;
141 if(del[y] || y == f) continue;
142 get_root(y, x);
143 siz[x] += siz[y];
144 large = std::max(large, siz[y]);
145 }
146 large = std::max(large, _n - siz[x]);
147 if(small > large) {
148 small = large;
149 root = x;
150 }
151 return;
152 }
153
154 void DFS_1(int x, int f, int rt) {
155 siz[x] = 1;
156 for(int i = e[x]; i; i = edge[i].nex) {
157 int y = edge[i].v;
158 if(del[y] || y == f) {
159 continue;
160 }
161 DFS_1(y, x, rt);
162 siz[x] += siz[y];
163 }
164 return;
165 }
166
167 void poi_div(int x, int f) {
168 small = INF;
169 get_root(x, 0);
170 x = root;
171 FA[x] = f;
172
173 for(int i = e[x]; i; i = edge[i].nex) {
174 int y = edge[i].v;
175 if(del[y]) continue;
176 DFS_1(y, x, x);
177 }
178
179 del[x] = 1;
180 for(int i = e[x]; i; i = edge[i].nex) {
181 int y = edge[i].v;
182 if(del[y]) continue;
183 _n = siz[y];
184 poi_div(y, x);
185 }
186
187 return;
188 }
189
190 inline void change(int x, int d, int v) {
191 int first_x = x;
192 while(x) {
193 int t = dis(x, first_x);
194 if(t <= d) {
195 seg::insert(x, 0, d - t, v);
196 }
197 if(FA[x]) {
198 t = dis(FA[x], first_x);
199 if(t <= d) {
200 seg::insert(x + n, 0, d - t, v);
201 }
202 }
203 x = FA[x];
204 }
205 return;
206 }
207
208 inline int ask(int x) {
209 int ans = 0, fisrt_x = x;
210 while(x) {
211 ans += seg::ask(x, dis(x, fisrt_x));
212 if(FA[x]) {
213 ans -= seg::ask(x + n, dis(FA[x], fisrt_x));
214 }
215 x = FA[x];
216 }
217 return ans;
218 }
219
220 int main() {
221
222 int q;
223 read(n); read(q);
224 for(int i = 1, x, y; i < n; i++) {
225 read(x); read(y);
226 add(x, y); add(y, x);
227 }
228
229 DFS_0(1, 0);
230 prework();
231 _n = n;
232 poi_div(1, 0);
233
234
235 for(int i = 1, x, y, z; i <= q; i++) {
236 scanf("%s", str);
237 if(str[0] == 'Q') {
238 read(x);
239 int t = ask(x);
240 printf("%d\n", t);
241 }
242 else {
243 read(x); read(y); read(z);
244 change(x, y, z);
245 }
246 }
247
248 return 0;
249 }
常数大伤不起啊...开了快读还差点T(或许是bzoj太慢?)
LOJ#6145 Easy
跟开店类似但是简单一些...(指点分树做法),然后我又1A了.......
求编号在[l, r]中的点到x的最短距离。
根据套路,我们考虑怎么统计答案:点分树上每个点维护它的点分子树中每个点到它的距离(这种信息是O(nlogn)的),要求区间取min。然后查询的时候跳父亲统计答案就行了。

1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4
5 const int N = 100010, INF = 0x3f3f3f3f, M = 25000010;
6
7 struct Edge {
8 int nex, v, len;
9 }edge[N << 1]; int tp;
10
11 int e[N], FA[N], siz[N], n, _n, root, small, lm, pos[N], ST[N << 1][20], num, pw[N << 1], deep[N], dist[N], d[N];
12 bool del[N];
13
14 inline void add(int x, int y, int z) {
15 tp++;
16 edge[tp].v = y;
17 edge[tp].len = z;
18 edge[tp].nex = e[x];
19 e[x] = tp;
20 return;
21 }
22
23 namespace seg {
24 int tot, small[M], ls[M], rs[M], rt[N];
25 inline void init() {
26 memset(small, 0x3f, sizeof(small));
27 return;
28 }
29 void add(int p, int v, int l, int r, int &o) {
30 if(!o) {
31 o = ++tot;
32 }
33 if(l == r) {
34 small[o] = std::min(small[o], v);
35 return;
36 }
37 int mid = (l + r) >> 1;
38 if(p <= mid) {
39 add(p, v, l, mid, ls[o]);
40 }
41 else {
42 add(p, v, mid + 1, r, rs[o]);
43 }
44 small[o] = std::min(small[ls[o]], small[rs[o]]);
45 return;
46 }
47 int getMin(int L, int R, int l, int r, int o) {
48 //printf("%d %d %d %d %d \n", L, R, l, r, o);
49 if(!o) return INF;
50 if(L <= l && r <= R) {
51 return small[o];
52 }
53 int mid = (l + r) >> 1, ans = INF;
54 if(L <= mid) {
55 ans = std::min(ans, getMin(L, R, l, mid, ls[o]));
56 }
57 if(mid < R) {
58 ans = std::min(ans, getMin(L, R, mid + 1, r, rs[o]));
59 }
60 return ans;
61 }
62 inline void insert(int id, int p, int v) {
63 //printf("insert : %d %d %d \n", id, p, v);
64 add(p, v, 1, n, rt[id]);
65 return;
66 }
67 inline int ask(int id, int l, int r) {
68 return getMin(l, r, 1, n, rt[id]);
69 }
70 }
71
72 void DFS_0(int x, int f) {
73 deep[x] = deep[f] + 1;
74 pos[x] = ++num;
75 ST[num][0] = x;
76 for(int i = e[x]; i; i = edge[i].nex) {
77 int y = edge[i].v;
78 if(y == f) continue;
79 dist[y] = dist[x] + edge[i].len;
80 DFS_0(y, x);
81 ST[++num][0] = x;
82 }
83 return;
84 }
85
86 inline void prework() {
87 for(int i = 2; i <= num; i++) {
88 pw[i] = pw[i >> 1] + 1;
89 }
90 for(int j = 1; j <= pw[num]; j++) {
91 for(int i = 1; i + (1 << j) - 1 <= num; i++) {
92 if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]])
93 ST[i][j] = ST[i][j - 1];
94 else
95 ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
96 }
97 }
98 return;
99 }
100
101 inline int lca(int x, int y) {
102 x = pos[x];
103 y = pos[y];
104 if(x > y) std::swap(x, y);
105 int t = pw[y - x + 1];
106 if(deep[ST[x][t]] < deep[ST[y - (1 << t) +1][t]])
107 return ST[x][t];
108 else
109 return ST[y - (1 << t) + 1][t];
110 }
111
112 inline int dis(int x, int y) {
113 return dist[x] + dist[y] - 2 * dist[lca(x, y)];
114 }
115
116 void get_root(int x, int f) {
117 siz[x] = 1;
118 int large = 0;
119 for(int i = e[x]; i; i = edge[i].nex) {
120 int y = edge[i].v;
121 if(del[y] || y == f) continue;
122 get_root(y, x);
123 large = std::max(large, siz[y]);
124 siz[x] += siz[y];
125 }
126 large = std::max(large, _n - siz[x]);
127 if(small > large) {
128 small = large;
129 root = x;
130 }
131 return;
132 }
133
134 void DFS_1(int x, int f, int rt) {
135 siz[x] = 1;
136 seg::insert(rt, x, d[x]);
137 for(int i = e[x]; i; i = edge[i].nex) {
138 int y = edge[i].v;
139 if(del[y] || y == f) continue;
140 d[y] = d[x] + edge[i].len;
141 DFS_1(y, x, rt);
142 siz[x] += siz[y];
143 }
144 return;
145 }
146
147 void poi_div(int x, int f) {
148 small = INF;
149 get_root(x, 0);
150 x = root;
151 FA[x] = f;
152
153 seg::insert(x, x, 0);
154 for(int i = e[x]; i; i = edge[i].nex) {
155 int y = edge[i].v;
156 if(del[y]) continue;
157 d[y] = edge[i].len;
158 DFS_1(y, x, x);
159 }
160
161 del[x] = 1;
162 for(int i = e[x]; i; i = edge[i].nex) {
163 int y = edge[i].v;
164 if(del[y]) continue;
165 _n = siz[y];
166 poi_div(y, x);
167 }
168 return;
169 }
170
171 inline int ask(int x, int L, int R) {
172 int first_x = x, ans = INF;
173 while(x) {
174 ans = std::min(ans, seg::ask(x, L, R) + dis(x, first_x));
175 //printf("%d + %d \n", seg::ask(x, L, R), dis(x, first_x));
176 x = FA[x];
177 }
178 return ans;
179 }
180
181 int main() {
182 scanf("%d", &n);
183 for(int i = 1, x, y, z; i < n; i++) {
184 scanf("%d%d%d", &x, &y, &z);
185 add(x, y, z); add(y, x, z);
186 lm += z;
187 }
188
189 DFS_0(1, 0);
190 prework();
191 seg::init();
192 _n = n;
193 poi_div(1, 0);
194
195 int q;
196 scanf("%d", &q);
197 for(int i = 1, l, r, x; i <= n; i++) {
198 scanf("%d%d%d", &l, &r, &x);
199 int t = ask(x, l, r);
200 printf("%d\n", t);
201 }
202
203 return 0;
204 }
洛谷P3920 紫荆花之恋
这个......卡常神题 + 码农神题。11.2k,500行还行。
一开始写的妃萱treap飞旋只有55分,换成splay有80分了,但是链的部分还是过不去。最后数据分治了一下终于A了......
动态加点,求树上dis(x, y) <= w[i] + w[j]的点对数量。
链的部分数据就直接用4棵平衡树,维护一下两边对两边分别的贡献即可。
考虑现在有个点分树,然后我们在原树和点分树下同时插入一个叶子。
推个式子,往上跳的时候统计一下答案,记得把FA[x]多算的答案减去,点分树经典套路了。
如果发现某一层的点分树子树过大,就暴力重构该子树,建出完全平衡点分子树。

1 #include <cstdio>
2 #include <cstdlib>
3 #include <algorithm>
4 #include <climits>
5
6 typedef long long LL;
7 const int N = 100010, M = 20000010, INF = 0x7f7f7f7f, MO = 1e9;
8 const double alpha = 0.8;
9
10 inline void read(int &x) {
11 x = 0;
12 char c = getchar();
13 while(c < '0' || c > '9') {
14 c = getchar();
15 }
16 while(c >= '0' && c <= '9') {
17 x = (x << 3) + (x << 1) + c - 48;
18 c = getchar();
19 }
20 return;
21 }
22
23 struct Edge {
24 int nex, v, len, pre;
25 }edge[N << 1], EDGE[N << 1]; int tp, TP;
26
27 int e[N], E[N], FA[N], fa[N][20], dist[N], n, root, _n, small, w[N], SIZ[N], rebuild;
28 int Time, ine[N], d[N], deep[N], pw[N], vis[N], siz[N], stkEDGE[N << 1], TOP, Cnt, ROOT;
29 LL ANS;
30 bool del[N];
31
32 namespace tree {
33 int tot, val[M], cnt[M], s[M][2], fa[M], siz[M], rt[N << 1], turn;
34 int stk[M], top;
35 inline int np(int v, int f) {
36 int x;
37 if(top) {
38 x = stk[top];
39 top--;
40 }
41 else {
42 x = ++tot;
43 }
44 cnt[x] = siz[x] = 1;
45 s[x][0] = s[x][1] = 0;
46 fa[x] = f;
47 val[x] = v;
48 return x;
49 }
50 inline void pushup(int x) {
51 siz[x] = siz[s[x][0]] + siz[s[x][1]] + cnt[x];
52 if(!fa[x]) rt[turn] = x;
53 return;
54 }
55 inline void rotate(int x) {
56 int y = fa[x];
57 int z = fa[y];
58 bool f = (s[y][1] == x);
59
60 fa[x] = z;
61 if(z) s[z][s[z][1] == y] = x;
62 s[y][f] = s[x][!f];
63 if(s[x][!f]) fa[s[x][!f]] = y;
64 s[x][!f] = y;
65 fa[y] = x;
66
67 pushup(y);
68 return;
69 }
70 inline void splay(int x, int g = 0) {
71 int y = fa[x];
72 int z = fa[y];
73 while(y != g) {
74 if(z != g) {
75 (s[z][1] == y) ^ (s[y][1] == x) ?
76 rotate(x) : rotate(y);
77 }
78 rotate(x);
79 y = fa[x];
80 z = fa[y];
81 }
82 pushup(x);
83 return;
84 }
85 inline void add(int id, int v) {
86 turn = id;
87 int p = rt[turn];
88 if(!p) {
89 rt[turn] = np(v, 0);
90 return;
91 }
92 while(1) {
93 siz[p]++;
94 if(val[p] == v) {
95 cnt[p]++;
96 break;
97 }
98 if(v < val[p] && s[p][0]) {
99 p = s[p][0];
100 }
101 else if(val[p] < v && s[p][1]) {
102 p = s[p][1];
103 }
104 else { /// insert node
105 bool f = (val[p] < v);
106 s[p][f] = np(v, p);
107 p = s[p][f];
108 break;
109 }
110 }
111 splay(p);
112 return;
113 }
114 inline int getPbyV(int v) {
115 int p = rt[turn];
116 while(1) {
117 if(val[p] == v) break;
118 if(v < val[p] && s[p][0]) p = s[p][0];
119 else if(val[p] < v && s[p][1]) p = s[p][1];
120 else break;
121 }
122 splay(p);
123 return p;
124 }
125 inline int ask(int id, int v) {
126 turn = id;
127 if(!rt[turn]) return 0;
128 int p = getPbyV(v);
129 if(val[p] <= v) return siz[s[p][0]] + cnt[p];
130 else return siz[s[p][0]];
131 }
132 void dfs(int x) {
133 if(s[x][0]) dfs(s[x][0]);
134 if(s[x][1]) dfs(s[x][1]);
135 stk[++top] = x;
136 return;
137 }
138 inline void del(int id) {
139 turn = id;
140 if(!rt[turn]) return;
141 dfs(rt[turn]);
142 rt[turn] = 0;
143 return;
144 }
145 }
146
147 namespace tree2 {
148 int tot, ls[M], rs[M], val[M], stk[M], rd[M], siz[M], top, rt[N << 1];
149 int np(int v) {
150 int o;
151 if(top) {
152 o = stk[top];
153 top--;
154 }
155 else {
156 o = ++tot;
157 }
158 val[o] = v;
159 rd[o] = (rand() * (1ll << 16) + rand()) % LONG_MAX;
160 siz[o] = 1;
161 ls[o] = rs[o] = 0;
162 return o;
163 }
164 int merge(int x, int y) {
165 if(!x || !y) return x | y;
166 if(rd[x] >= rd[y]) {
167 rs[x] = merge(rs[x], y);
168 siz[x] = siz[ls[x]] + siz[rs[x]] + 1;
169 return x;
170 }
171 else {
172 ls[y] = merge(x, ls[y]);
173 siz[y] = siz[ls[y]] + siz[rs[y]] + 1;
174 return y;
175 }
176 }
177 void splitV(int o, int k, int &x, int &y) {
178 if(!o) {
179 x = y = 0;
180 return;
181 }
182 if(val[o] <= k) {
183 x = o;
184 splitV(rs[x], k, rs[x], y);
185 }
186 else {
187 y = o;
188 splitV(ls[y], k, x, ls[y]);
189 }
190 siz[o] = siz[ls[o]] + siz[rs[o]] + 1;
191 return;
192 }
193 inline void add(int id, int v) {
194 int x, y;
195 splitV(rt[id], v, x, y);
196 rt[id] = merge(merge(x, np(v)), y);
197 return;
198 }
199 inline int ask(int id, int v) {
200 int x, y;
201 splitV(rt[id], v, x, y);
202 int ans = siz[x];
203 rt[id] = merge(x, y);
204 return ans;
205 }
206 void dfs(int x) {
207 if(ls[x]) dfs(ls[x]);
208 if(rs[x]) dfs(rs[x]);
209 stk[++top] = x;
210 return;
211 }
212 inline void del(int id) {
213 if(rt[id]) {
214 dfs(rt[id]);
215 rt[id] = 0;
216 }
217 return;
218 }
219 }
220
221 void out(int x) {
222 printf("x = %d \n", x);
223 for(int i = E[x]; i; i = EDGE[i].nex) {
224 int y = EDGE[i].v;
225 printf(" x = %d y = %d in_E_check %d\n", x, y, ine[y] == i);
226 out(y);
227 }
228 return;
229 }
230
231 inline void add(int x, int y, int z) {
232 tp++;
233 edge[tp].v = y;
234 edge[tp].len = z;
235 edge[tp].nex = e[x];
236 edge[e[x]].pre = tp;
237 e[x] = tp;
238 return;
239 }
240
241 inline void ADD(int x, int y) {
242 int o;
243 if(TOP) {
244 o = stkEDGE[TOP];
245 TOP--;
246 }
247 else {
248 o = ++TP;
249 }
250 EDGE[o].v = y;
251 EDGE[o].nex = E[x];
252 EDGE[o].pre = 0;
253 EDGE[E[x]].pre = o;
254 E[x] = o;
255 ine[y] = o;
256 return;
257 }
258
259 inline void delPoi(int x) {
260 for(register int i = E[x]; i; i = EDGE[i].nex) {
261 stkEDGE[++TOP] = i;
262 }
263 E[x] = 0;
264 return;
265 }
266
267 inline void delEDGE(int i, int x) {
268 if(!EDGE[i].pre && !EDGE[i].nex) {
269 E[x] = 0;
270 return;
271 }
272 if(!EDGE[i].pre) {
273 E[x] = EDGE[i].nex;
274 EDGE[EDGE[i].nex].pre = 0;
275 return;
276 }
277 if(!EDGE[i].nex) {
278 EDGE[EDGE[i].pre].nex = 0;
279 return;
280 }
281 EDGE[EDGE[i].pre].nex = EDGE[i].nex;
282 EDGE[EDGE[i].nex].pre = EDGE[i].pre;
283 stkEDGE[++TOP] = i;
284 return;
285 }
286
287 inline int lca(int x, int y) {
288 if(deep[x] > deep[y]) std::swap(x, y);
289 int t = pw[n];
290 while(t >= 0 && deep[x] < deep[y]) {
291 if(deep[fa[y][t]] >= deep[x]) {
292 y = fa[y][t];
293 }
294 t--;
295 }
296 if(x == y) return x;
297 t = pw[n];
298 while(t >= 0 && fa[x][0] != fa[y][0]) {
299 if(fa[x][t] != fa[y][t]) {
300 x = fa[x][t];
301 y = fa[y][t];
302 }
303 t--;
304 }
305 return fa[x][0];
306 }
307
308 inline int dis(int x, int y) {
309 return dist[x] - 2 * dist[lca(x, y)] + dist[y];
310 }
311
312 void DFS_0(int x) {
313 vis[x] = Time;
314 del[x] = 0;
315 tree::del(x);
316 tree::del(x + n);
317 Cnt++;
318 for(register int i = E[x]; i; i = EDGE[i].nex) {
319 int y = EDGE[i].v;
320 DFS_0(y);
321 }
322 delPoi(x);
323 return;
324 }
325
326 void get_root(int x, int f) {
327 siz[x] = 1;
328 int large = 0;
329 for(register int i = e[x]; i; i = edge[i].nex) {
330 int y = edge[i].v;
331 if(del[y] || y == f || vis[y] != Time) {
332 continue;
333 }
334 get_root(y, x);
335 siz[x] += siz[y];
336 large = std::max(large, siz[y]);
337 }
338 large = std::max(large, _n - siz[x]);
339 if(small > large) {
340 small = large;
341 root = x;
342 }
343 return;
344 }
345
346 void DFS_1(int x, int f, int rt) {
347 siz[x] = 1;
348 tree::add(rt, d[x] - w[x]);
349 if(FA[rt]) {
350 tree::add(rt + n, dis(x, FA[rt]) - w[x]);
351 }
352 for(register int i = e[x]; i; i = edge[i].nex) {
353 int y = edge[i].v;
354 if(del[y] || vis[y] != Time || y == f) {
355 continue;
356 }
357 d[y] = d[x] + edge[i].len;
358 DFS_1(y, x, rt);
359 siz[x] += siz[y];
360 }
361 return;
362 }
363
364 void poi_div(int x, int f) {
365 small = INF;
366 get_root(x, 0);
367 x = root;
368 FA[x] = f;
369 if(!f) ROOT = x;
370 ADD(f, x);
371
372 SIZ[x] = 1;
373 tree::add(x, -w[x]);
374 if(f) {
375 tree::add(x + n, dis(x, f) - w[x]);
376 }
377 for(register int i = e[x]; i; i = edge[i].nex) {
378 int y = edge[i].v;
379 if(del[y] || vis[y] != Time) {
380 continue;
381 }
382 d[y] = edge[i].len;
383 DFS_1(y, x, x);
384 SIZ[x] += siz[y];
385 }
386
387 del[x] = 1;
388 for(register int i = e[x]; i; i = edge[i].nex) {
389 int y = edge[i].v;
390 if(del[y] || vis[y] != Time) {
391 continue;
392 }
393 _n = siz[y];
394 poi_div(y, x);
395 }
396 return;
397 }
398
399 inline void solve(int x) {
400 Time++;
401 Cnt = 0;
402 DFS_0(x); /// get point to rebuild
403 if(FA[x]) {
404 delEDGE(ine[x], FA[x]);
405 }
406 _n = Cnt;
407 poi_div(x, FA[x]);
408 return;
409 }
410
411 inline void insert(int x, int f, int d) {
412 if(!f) {
413 SIZ[x] = 1;
414 deep[x] = 1;
415 ROOT = 1;
416 tree::add(x, -w[x]);
417 return;
418 }
419
420 fa[x][0] = f;
421 for(register int j = 1; j <= pw[x]; j++) {
422 fa[x][j] = fa[fa[x][j - 1]][j - 1];
423 }
424 dist[x] = dist[f] + d;
425 deep[x] = deep[f] + 1;
426 add(x, f, d); add(f, x, d);
427
428 FA[x] = f;
429 ADD(f, x);
430
431 f = x;
432 while(f) {
433 SIZ[f]++;
434 int temp = dis(x, f) - w[x];
435 ANS += tree::ask(f, -temp); /// how many not larger than v
436 if(FA[f]) {
437 int t2 = dis(FA[f], x) - w[x];
438 ANS -= tree::ask(f + n, -t2); /// the repeat count
439 tree::add(f + n, t2);
440 }
441 tree::add(f, temp);
442 if(FA[f] && SIZ[f] > (SIZ[FA[f]] + 1) * alpha) {
443 rebuild = FA[f];
444 }
445 f = FA[f];
446 }
447
448 if(rebuild) {
449 solve(rebuild);
450 rebuild = 0;
451 }
452 return;
453 }
454
455 #define Left 1
456 #define Right 2
457 namespace line {
458 int dir[N], F;
459 inline void insert(int x, int f, int d) {
460 if(!f) {
461 return;
462 }
463 if(dir[f]) dir[x] = dir[f];
464 else {
465 if(x == 2) dir[x] = Left;
466 else dir[x] = Right;
467 }
468 dist[x] = dist[f] + d;
469 ANS += tree::ask(dir[x], w[x] - dist[x]);
470 tree::add(3 - dir[x], dist[x] - w[x]);
471 ANS += tree::ask(dir[x] + 2, w[x] - dist[x]);
472 tree::add(dir[x] + 2, -w[x] - dist[x]);
473 if(dist[x] <= w[x] + w[1]) ANS++;
474 return;
475 }
476 }
477 #undef Left
478 #undef Right
479
480 int main() {
481
482 read(n);
483 bool F = n >= 5 && n <= 8;
484 read(n);
485 for(register int i = 2; i <= n; i++)
486 pw[i] = pw[i >> 1] + 1;
487 int x, y;
488 for(register int i = 1; i <= n; i++) {
489 read(x); read(y); read(w[i]);
490 x ^= (ANS % MO);
491 F ? line::insert(i, x, y) : insert(i, x, y);
492 printf("%lld\n", ANS);
493 }
494 return 0;
495 }
开店留着复习用。
来源:https://www.cnblogs.com/huyufeifei/p/10426796.html
