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...

 #include <bits/stdc++.h>

 using namespace std;

 typedef long long ll;

 const int N = 1e5 + ;

 int n, m, tot, head[N];

 int fa[N], siz[N], dep[N];

 int cnt, son[N], top[N], dfn[N], st[N], en[N];

 int nowD, lx, ly, rx, ry, val;

 ll ans;

 struct edge{int to, next;}e[N];

 struct node {
ll siz, val, sum, lazy1, lazy2;
int maxd[], mind[], d[];
node *c[]; node() {
val = sum = siz = , lazy1 = , lazy2 = -;
c[] = c[] = NULL;
} void update(); void pushup(); void pushdown(); bool operator < (const node &a) const {
return d[nowD] < a.d[nowD];
}
}nodes[N]; node *null = new node; node *root; inline void node::update() {
if (c[] != null) {
if (c[] -> maxd[] > maxd[]) maxd[] = c[] -> maxd[];
if (c[] -> maxd[] > maxd[]) maxd[] = c[] -> maxd[];
if (c[] -> mind[] < mind[]) mind[] = c[] -> mind[];
if (c[] -> mind[] < mind[]) mind[] = c[] -> mind[];
}
if (c[] != null) {
if (c[] -> maxd[] > maxd[]) maxd[] = c[] -> maxd[];
if (c[] -> maxd[] > maxd[]) maxd[] = c[] -> maxd[];
if (c[] -> mind[] < mind[]) mind[] = c[] -> mind[];
if (c[] -> mind[] < mind[]) mind[] = c[] -> mind[];
}
siz = + c[] -> siz + c[] -> siz;
} inline void node::pushup() {
sum = val + c[] -> sum + c[] -> sum;
} inline void node::pushdown() {
if (lazy1 == && lazy2 == -) return;
if (lazy1 != ) {
if (c[] != null) {
c[] -> val += lazy1;
c[] -> sum += c[] -> siz * lazy1;
if (c[] -> lazy2 != -) c[] -> lazy2 += lazy1;
else c[] -> lazy1 += lazy1;
}
if (c[] != null) {
c[] -> val += lazy1;
c[] -> sum += c[] -> siz * lazy1;
if (c[] -> lazy2 != -) c[] -> lazy2 += lazy1;
else c[] -> lazy1 += lazy1;
}
lazy1 = ;
return;
}
if (lazy2 != -) {
if (c[] != null) {
c[] -> val = lazy2;
c[] -> sum = c[] -> siz * lazy2;
c[] -> lazy1 = ;
c[] -> lazy2 = lazy2;
}
if (c[] != null) {
c[] -> val = lazy2;
c[] -> sum = c[] -> siz * lazy2;
c[] -> lazy1 = ;
c[] -> lazy2 = lazy2;
}
lazy2 = -;
return;
}
} inline void dfs1(int u) {
siz[u] = ;
for (int v, i = head[u]; i; i = e[i].next) {
v = e[i].to, fa[v] = u;
dep[v] = dep[u] + ;
dfs1(v), siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
} inline void dfs2(int u, int tp) {
dfn[++ cnt] = u, st[u] = cnt, top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (int v, i = head[u]; i; i = e[i].next) {
v = e[i].to;
if (v != son[u]) dfs2(v, v);
}
en[u] = cnt;
} inline node *build(int l, int r, int D) {
int mid = l + r >> ; nowD = D;
nth_element(nodes + l, nodes + mid, nodes + r);
node *res = &nodes[mid];
if (l != mid) res -> c[] = build(l, mid - , !D);
else res -> c[] = null;
if (r != mid) res -> c[] = build(mid + , r, !D);
else res -> c[] = null;
res -> update();
return res;
} inline void query1(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || ly > o -> maxd[] || rx < o -> mind[] || ry < o -> mind[])
return;
if (lx <= o -> mind[] && ly <= o -> mind[] && rx >= o -> maxd[]&& ry >= o -> maxd[]) {
ans += o -> sum;
return;
}
if (lx <= o -> d[] && rx >= o -> d[] && ly <= o -> d[] && ry >= o -> d[])
ans += o -> val;
o -> pushdown();
query1(o -> c[]), query1(o -> c[]);
} inline void modify2(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || ly > o -> maxd[] || rx < o -> mind[] || ry < o -> mind[])
return;
if (lx <= o -> mind[] && ly <= o -> mind[] && rx >= o -> maxd[] && ry >= o -> maxd[]) {
if (o -> lazy2 != -) o -> lazy2 += val;
else o -> lazy1 += val;
o -> sum += o -> siz * val;
o -> val += val;
return;
}
if (lx <= o -> d[] && rx >= o -> d[] && ly <= o -> d[] && ry >= o -> d[])
o -> val += val;
o -> pushdown();
modify2(o -> c[]), modify2(o -> c[]);
o -> pushup();
} inline void modify3(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || ly > o -> maxd[] || rx < o -> mind[] || ry < o -> mind[])
return;
if (lx <= o -> mind[] && ly <= o -> mind[] && rx >= o -> maxd[] && ry >= o -> maxd[]) {
o -> lazy1 = , o -> lazy2 = val;
o -> val = val, o -> sum = o -> siz * val;
return;
}
if (lx <= o -> d[] && rx >= o -> d[] && ly <= o -> d[] && ry >= o -> d[])
o -> val = val;
o -> pushdown();
modify3(o -> c[]), modify3(o -> c[]);
o -> pushup();
} inline void ask4(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || rx < o -> mind[]) return;
if (lx <= o -> mind[] && rx >= o -> maxd[]) {
ans += o -> sum;
return;
}
if (lx <= o -> d[] && rx >= o -> d[]) ans += o -> val;
o -> pushdown();
ask4(o -> c[]), ask4(o -> c[]);
} inline void query4(int u) {
for (int fu = top[u]; fu != ; fu = top[u = fa[fu]])
lx = st[fu], rx = st[u], ask4(root);
lx = , rx = st[u], ask4(root);
} inline void change5(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || rx < o -> mind[])
return;
if (lx <= o -> mind[] && rx >= o -> maxd[]) {
if (o -> lazy2 != -) o -> lazy2 += val;
else o -> lazy1 += val;
o -> sum += o -> siz * val;
o -> val += val;
return;
}
if (lx <= o -> d[] && rx >= o -> d[])
o -> val += val;
o -> pushdown();
change5(o -> c[]), change5(o -> c[]);
o -> pushup();
} inline void change6(node *o) {
if (o == null) return;
if (lx > o -> maxd[] || rx < o -> mind[]) return;
if (lx <= o -> mind[] && rx >= o -> maxd[]) {
o -> lazy1 = , o -> lazy2 = val;
o -> val = val, o -> sum = o -> siz * val;
return;
}
if (lx <= o -> d[] && rx >= o -> d[])
o -> val = val;
o -> pushdown();
change6(o -> c[]), change6(o -> c[]);
o -> pushup();
} inline void modify5(int u) {
for (int fu = top[u]; fu != ; fu = top[u = fa[fu]])
lx = st[fu], rx = st[u], change5(root);
lx = , rx = st[u], change5(root);
} inline void modify6(int u) {
for (int fu = top[u]; fu != ; fu = top[u = fa[fu]])
lx = st[fu], rx = st[u], change6(root);
lx = , rx = st[u], change6(root);
} int main() {
ios::sync_with_stdio(false);
int testCase, op, u, l, r;
cin >> testCase >> n;
for (int j, i = ; i <= n; i ++)
cin >> j, e[++ tot] = {i, head[j]}, head[j] = tot;
dfs1(), dfs2(, );
for (int i = ; i <= n; i ++) {
nodes[i].d[] = nodes[i].maxd[] = nodes[i].mind[] = i;
nodes[i].d[] = nodes[i].maxd[] = nodes[i].mind[] = dep[dfn[i]];
nodes[i].val = nodes[i].sum = , nodes[i].lazy1 = , nodes[i].lazy2 = -;
}
root = build(, n, );
for (cin >> m; m --; ) {
cin >> op;
switch(op) {
case :
cin >> u >> l >> r;
lx = st[u], ly = dep[u] + l;
rx = en[u], ry = dep[u] + r;
ans = , query1(root), cout << ans << endl;
break;
case :
cin >> u >> l >> r >> val;
lx = st[u], ly = dep[u] + l;
rx = en[u], ry = dep[u] + r;
modify2(root);
break;
case :
cin >> u >> l >> r >> val;
lx = st[u], ly = dep[u] + l;
rx = en[u], ry = dep[u] + r;
modify3(root);
break;
case :
cin >> u, ans = ;
query4(u), cout << ans << endl;
break;
case :
cin >> u >> val;
modify5(u);
break;
case :
cin >> u >> val;
modify6(u);
break;
}
}
return ;
}

代码细节:

kdtree指针跑的比数组快,在数组比较大的时候速度差距比较明显

kdtree的这个update写法是固定的,必须要判左右儿子非null才更新,(后续更新需要调用update的情况下)常数大概是一倍

update其实是可以和pushup合并为用同一个函数的,但考虑后续修改只修改值不修改每个点的二维坐标,所以我分开了(1s的差距)

change5和change6是可以被modify2和modify3替代的,当然这时候要在modify5和modify6里对ly和ry两个变量也做调整

bzoj 5355 kdtree 树链剖分的更多相关文章

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

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  2. BZOJ 3083 遥远的国度 树链剖分

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Descrip ...

  3. BZOJ 2157: 旅游( 树链剖分 )

    树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...

  4. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  5. BZOJ 2157 旅行(树链剖分码农题)

    写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...

  6. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

  7. BZOJ 3083 遥远的国度 树链剖分+线段树

    有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...

  8. BZOJ 2243 染色 树链剖分

    题意: 给出一棵树,每个顶点上有个颜色\(c_i\). 有两种操作: C a b c 将\(a \to b\)的路径所有顶点上的颜色变为c Q a b 查询\(a \to b\)的路径上的颜色段数,连 ...

  9. BZOJ 3626 离线+树链剖分+线段树

    思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...

随机推荐

  1. java dom4j 读写XML

    <?xml version="1.0" encoding="UTF-8"?> <Configuration> <Config id ...

  2. [linux环境配置]个人用持续更新ing~

    alias ll='ls -la' export PATH=$PATH:~/Desktop/myscript alias gpush='git push origin HEAD:refs/for/ma ...

  3. poi导出excel改变标题颜色

    在excelutil类里面添加 public class ExcelUtil { public static Workbook fillExcelData(ResultSet rs, Workbook ...

  4. C# 的反射和映射

    最近想研究一下反射,先上网找了找资料,几乎大部分都是照抄MSDN的内容,生涩难懂,几乎没说,又找了找,发现一些强人的实例解析,才稍微有了 点门道,个人感觉,反射其实就是为了能够在程序运行期间动态的加载 ...

  5. An problem about date 根据年月日计算 星期几

    /W = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7(1.2月需要看作上一年的13.14月) #include<stdio.h> #include& ...

  6. vagrant使用centos的环境安装..

    vagrant这货挺好用的..简要就是, 下好virtualbox, vagrant, 然后下个你需要的box. 然后vagrant box add boxname boxpath就行. 然后在合适的 ...

  7. ACM_出题人这样不好吧

    出题人这样不好吧 Time Limit: 2000/1000ms (Java/Others) Problem Description: 作为编协的第一次月赛,肯定是要有防AK(ALL KILL)的题目 ...

  8. 题解报告:poj 3233 Matrix Power Series(矩阵快速幂)

    题目链接:http://poj.org/problem?id=3233 Description Given a n × n matrix A and a positive integer k, fin ...

  9. nginx下如何配置 ssl证书?腾讯云ssl证书为例!

    nginx下如何配置 ssl证书?腾讯云ssl证书为例! 目前为止,https已经成为一种趋势,想要开启https就需要ssl证书. 首先,为域名注册ssl证书. 腾讯云注册地址:https://cl ...

  10. Android项目实战_手机安全卫士home界面

    # 安全卫士主页面# ###1.GridView控件 1.与ListView的使用方式差不多,也要使用数据适配器,通过设置android:numColumns控制显示几列 2.通过指定android: ...