bzoj 5355 kdtree 树链剖分

Posted ytytzzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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两个变量也做调整

以上是关于bzoj 5355 kdtree 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2243 染色 | 树链剖分模板题进阶版

BZOJ2157: 旅游 树链剖分 线段树

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

BZOJ 2157 旅游(树链剖分+线段树)

bzoj 1036 树链剖分+线段树 裸题

bzoj4712 -- 树链剖分