动态点分治
大概就是把点分树建出来,维护每个点的信息和全局信息。
修改的时候考虑一个点对它点分树祖先的影响。
树上与距离有关的问题,考虑动态点分治。
例题:
洛谷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 }
开店留着复习用。