动态点分治

大概就是把点分树建出来,维护每个点的信息和全局信息。

修改的时候考虑一个点对它点分树祖先的影响。

树上与距离有关的问题,考虑动态点分治。

例题:

洛谷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 
", 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 
", 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 
", 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 
", 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 
", 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
", getAns());
287         }
288         else {
289             read(x);
290             change(x);
291         }
292     }
293 
294     return 0;
295 }
AC代码

感觉动态点分治主要是难在理清思路上......

洛谷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
", t);
235     }
236 
237     return 0;
238 }
AC代码

对拍真是个好东西...

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 
", 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 
", 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 
", 0, k - dis(FA[x], first_x), seg::ask(x + n, 0, k - dis(FA[x], first_x)));
200         }
201         //printf("%d %d 
", 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 
", 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
", lastans);
236         }
237         else { /// change
238             change(x, y);
239         }
240     }
241 
242     return 0;
243 }
AC代码

差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
", t);
241         }
242         else {
243             read(x); read(y); read(z);
244             change(x, y, z);
245         }
246     }
247 
248     return 0;
249 }
AC代码

常数大伤不起啊...开了快读还差点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 
", 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 
", 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 
", 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
", t);
201     }
202 
203     return 0;
204 }
AC代码

洛谷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 
", 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
", 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
", ANS);
493     }
494     return 0;
495 }
AC代码

开店留着复习用。

原文地址:https://www.cnblogs.com/huyufeifei/p/10426796.html