bzoj 5355 kdtree 树链剖分
https://www.lydsy.com/JudgeOnline/problem.php?id=5355
想在b站搜query on a tree系列不小心看到了这题
扑鼻而来的浓浓的OI风格的题面,6个操作,放在ACM界读完题就可以喷了(误
看到前三个操作...kdtree板子题,一维dfs序,一维dep,限制区间显然
后面三个操作...考虑树链剖分,这样点到根的路径就是几条不连续的链了
就把前面kdtree的一维dfs序换成树链剖分的方法得到的dfs序就行了
对于后面三个操作相当于把常写的树链剖分套线段树的线段树换成kdtree了
复杂度O(n*sqrt(n)*logn),这样的话为什么后面三个操作不直接对树上路径进行操作呢...
写这个题...单纯为了一时爽...尤其是过了样例一发入魂的那种 feel...
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int N = 1e5 + 5; 8 9 int n, m, tot, head[N]; 10 11 int fa[N], siz[N], dep[N]; 12 13 int cnt, son[N], top[N], dfn[N], st[N], en[N]; 14 15 int nowD, lx, ly, rx, ry, val; 16 17 ll ans; 18 19 struct edge{int to, next;}e[N]; 20 21 struct node { 22 ll siz, val, sum, lazy1, lazy2; 23 int maxd[2], mind[2], d[2]; 24 node *c[2]; 25 26 node() { 27 val = sum = siz = 0, lazy1 = 0, lazy2 = -1; 28 c[0] = c[1] = NULL; 29 } 30 31 void update(); 32 33 void pushup(); 34 35 void pushdown(); 36 37 bool operator < (const node &a) const { 38 return d[nowD] < a.d[nowD]; 39 } 40 }nodes[N]; 41 42 node *null = new node; 43 44 node *root; 45 46 inline void node::update() { 47 if (c[0] != null) { 48 if (c[0] -> maxd[0] > maxd[0]) maxd[0] = c[0] -> maxd[0]; 49 if (c[0] -> maxd[1] > maxd[1]) maxd[1] = c[0] -> maxd[1]; 50 if (c[0] -> mind[0] < mind[0]) mind[0] = c[0] -> mind[0]; 51 if (c[0] -> mind[1] < mind[1]) mind[1] = c[0] -> mind[1]; 52 } 53 if (c[1] != null) { 54 if (c[1] -> maxd[0] > maxd[0]) maxd[0] = c[1] -> maxd[0]; 55 if (c[1] -> maxd[1] > maxd[1]) maxd[1] = c[1] -> maxd[1]; 56 if (c[1] -> mind[0] < mind[0]) mind[0] = c[1] -> mind[0]; 57 if (c[1] -> mind[1] < mind[1]) mind[1] = c[1] -> mind[1]; 58 } 59 siz = 1 + c[0] -> siz + c[1] -> siz; 60 } 61 62 inline void node::pushup() { 63 sum = val + c[0] -> sum + c[1] -> sum; 64 } 65 66 inline void node::pushdown() { 67 if (lazy1 == 0 && lazy2 == -1) return; 68 if (lazy1 != 0) { 69 if (c[0] != null) { 70 c[0] -> val += lazy1; 71 c[0] -> sum += c[0] -> siz * lazy1; 72 if (c[0] -> lazy2 != -1) c[0] -> lazy2 += lazy1; 73 else c[0] -> lazy1 += lazy1; 74 } 75 if (c[1] != null) { 76 c[1] -> val += lazy1; 77 c[1] -> sum += c[1] -> siz * lazy1; 78 if (c[1] -> lazy2 != -1) c[1] -> lazy2 += lazy1; 79 else c[1] -> lazy1 += lazy1; 80 } 81 lazy1 = 0; 82 return; 83 } 84 if (lazy2 != -1) { 85 if (c[0] != null) { 86 c[0] -> val = lazy2; 87 c[0] -> sum = c[0] -> siz * lazy2; 88 c[0] -> lazy1 = 0; 89 c[0] -> lazy2 = lazy2; 90 } 91 if (c[1] != null) { 92 c[1] -> val = lazy2; 93 c[1] -> sum = c[1] -> siz * lazy2; 94 c[1] -> lazy1 = 0; 95 c[1] -> lazy2 = lazy2; 96 } 97 lazy2 = -1; 98 return; 99 } 100 } 101 102 inline void dfs1(int u) { 103 siz[u] = 1; 104 for (int v, i = head[u]; i; i = e[i].next) { 105 v = e[i].to, fa[v] = u; 106 dep[v] = dep[u] + 1; 107 dfs1(v), siz[u] += siz[v]; 108 if (siz[v] > siz[son[u]]) son[u] = v; 109 } 110 } 111 112 inline void dfs2(int u, int tp) { 113 dfn[++ cnt] = u, st[u] = cnt, top[u] = tp; 114 if (son[u]) dfs2(son[u], tp); 115 for (int v, i = head[u]; i; i = e[i].next) { 116 v = e[i].to; 117 if (v != son[u]) dfs2(v, v); 118 } 119 en[u] = cnt; 120 } 121 122 inline node *build(int l, int r, int D) { 123 int mid = l + r >> 1; nowD = D; 124 nth_element(nodes + l, nodes + mid, nodes + r); 125 node *res = &nodes[mid]; 126 if (l != mid) res -> c[0] = build(l, mid - 1, !D); 127 else res -> c[0] = null; 128 if (r != mid) res -> c[1] = build(mid + 1, r, !D); 129 else res -> c[1] = null; 130 res -> update(); 131 return res; 132 } 133 134 inline void query1(node *o) { 135 if (o == null) return; 136 if (lx > o -> maxd[0] || ly > o -> maxd[1] || rx < o -> mind[0] || ry < o -> mind[1]) 137 return; 138 if (lx <= o -> mind[0] && ly <= o -> mind[1] && rx >= o -> maxd[0]&& ry >= o -> maxd[1]) { 139 ans += o -> sum; 140 return; 141 } 142 if (lx <= o -> d[0] && rx >= o -> d[0] && ly <= o -> d[1] && ry >= o -> d[1]) 143 ans += o -> val; 144 o -> pushdown(); 145 query1(o -> c[0]), query1(o -> c[1]); 146 } 147 148 inline void modify2(node *o) { 149 if (o == null) return; 150 if (lx > o -> maxd[0] || ly > o -> maxd[1] || rx < o -> mind[0] || ry < o -> mind[1]) 151 return; 152 if (lx <= o -> mind[0] && ly <= o -> mind[1] && rx >= o -> maxd[0] && ry >= o -> maxd[1]) { 153 if (o -> lazy2 != -1) o -> lazy2 += val; 154 else o -> lazy1 += val; 155 o -> sum += o -> siz * val; 156 o -> val += val; 157 return; 158 } 159 if (lx <= o -> d[0] && rx >= o -> d[0] && ly <= o -> d[1] && ry >= o -> d[1]) 160 o -> val += val; 161 o -> pushdown(); 162 modify2(o -> c[0]), modify2(o -> c[1]); 163 o -> pushup(); 164 } 165 166 inline void modify3(node *o) { 167 if (o == null) return; 168 if (lx > o -> maxd[0] || ly > o -> maxd[1] || rx < o -> mind[0] || ry < o -> mind[1]) 169 return; 170 if (lx <= o -> mind[0] && ly <= o -> mind[1] && rx >= o -> maxd[0] && ry >= o -> maxd[1]) { 171 o -> lazy1 = 0, o -> lazy2 = val; 172 o -> val = val, o -> sum = o -> siz * val; 173 return; 174 } 175 if (lx <= o -> d[0] && rx >= o -> d[0] && ly <= o -> d[1] && ry >= o -> d[1]) 176 o -> val = val; 177 o -> pushdown(); 178 modify3(o -> c[0]), modify3(o -> c[1]); 179 o -> pushup(); 180 } 181 182 inline void ask4(node *o) { 183 if (o == null) return; 184 if (lx > o -> maxd[0] || rx < o -> mind[0]) return; 185 if (lx <= o -> mind[0] && rx >= o -> maxd[0]) { 186 ans += o -> sum; 187 return; 188 } 189 if (lx <= o -> d[0] && rx >= o -> d[0]) ans += o -> val; 190 o -> pushdown(); 191 ask4(o -> c[0]), ask4(o -> c[1]); 192 } 193 194 inline void query4(int u) { 195 for (int fu = top[u]; fu != 1; fu = top[u = fa[fu]]) 196 lx = st[fu], rx = st[u], ask4(root); 197 lx = 1, rx = st[u], ask4(root); 198 } 199 200 inline void change5(node *o) { 201 if (o == null) return; 202 if (lx > o -> maxd[0] || rx < o -> mind[0]) 203 return; 204 if (lx <= o -> mind[0] && rx >= o -> maxd[0]) { 205 if (o -> lazy2 != -1) o -> lazy2 += val; 206 else o -> lazy1 += val; 207 o -> sum += o -> siz * val; 208 o -> val += val; 209 return; 210 } 211 if (lx <= o -> d[0] && rx >= o -> d[0]) 212 o -> val += val; 213 o -> pushdown(); 214 change5(o -> c[0]), change5(o -> c[1]); 215 o -> pushup(); 216 } 217 218 inline void change6(node *o) { 219 if (o == null) return; 220 if (lx > o -> maxd[0] || rx < o -> mind[0]) return; 221 if (lx <= o -> mind[0] && rx >= o -> maxd[0]) { 222 o -> lazy1 = 0, o -> lazy2 = val; 223 o -> val = val, o -> sum = o -> siz * val; 224 return; 225 } 226 if (lx <= o -> d[0] && rx >= o -> d[0]) 227 o -> val = val; 228 o -> pushdown(); 229 change6(o -> c[0]), change6(o -> c[1]); 230 o -> pushup(); 231 } 232 233 inline void modify5(int u) { 234 for (int fu = top[u]; fu != 1; fu = top[u = fa[fu]]) 235 lx = st[fu], rx = st[u], change5(root); 236 lx = 1, rx = st[u], change5(root); 237 } 238 239 inline void modify6(int u) { 240 for (int fu = top[u]; fu != 1; fu = top[u = fa[fu]]) 241 lx = st[fu], rx = st[u], change6(root); 242 lx = 1, rx = st[u], change6(root); 243 } 244 245 int main() { 246 ios::sync_with_stdio(false); 247 int testCase, op, u, l, r; 248 cin >> testCase >> n; 249 for (int j, i = 2; i <= n; i ++) 250 cin >> j, e[++ tot] = {i, head[j]}, head[j] = tot; 251 dfs1(1), dfs2(1, 1); 252 for (int i = 1; i <= n; i ++) { 253 nodes[i].d[0] = nodes[i].maxd[0] = nodes[i].mind[0] = i; 254 nodes[i].d[1] = nodes[i].maxd[1] = nodes[i].mind[1] = dep[dfn[i]]; 255 nodes[i].val = nodes[i].sum = 0, nodes[i].lazy1 = 0, nodes[i].lazy2 = -1; 256 } 257 root = build(1, n, 0); 258 for (cin >> m; m --; ) { 259 cin >> op; 260 switch(op) { 261 case 1: 262 cin >> u >> l >> r; 263 lx = st[u], ly = dep[u] + l; 264 rx = en[u], ry = dep[u] + r; 265 ans = 0, query1(root), cout << ans << endl; 266 break; 267 case 2: 268 cin >> u >> l >> r >> val; 269 lx = st[u], ly = dep[u] + l; 270 rx = en[u], ry = dep[u] + r; 271 modify2(root); 272 break; 273 case 3: 274 cin >> u >> l >> r >> val; 275 lx = st[u], ly = dep[u] + l; 276 rx = en[u], ry = dep[u] + r; 277 modify3(root); 278 break; 279 case 4: 280 cin >> u, ans = 0; 281 query4(u), cout << ans << endl; 282 break; 283 case 5: 284 cin >> u >> val; 285 modify5(u); 286 break; 287 case 6: 288 cin >> u >> val; 289 modify6(u); 290 break; 291 } 292 } 293 return 0; 294 }
代码细节:
kdtree指针跑的比数组快,在数组比较大的时候速度差距比较明显
kdtree的这个update写法是固定的,必须要判左右儿子非null才更新,(后续更新需要调用update的情况下)常数大概是一倍
update其实是可以和pushup合并为用同一个函数的,但考虑后续修改只修改值不修改每个点的二维坐标,所以我分开了(1s的差距)
change5和change6是可以被modify2和modify3替代的,当然这时候要在modify5和modify6里对ly和ry两个变量也做调整