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...
#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 树链剖分的更多相关文章
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- BZOJ 3083 遥远的国度 树链剖分
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 797 Solved: 181[Submit][Status] Descrip ...
- BZOJ 2157: 旅游( 树链剖分 )
树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- BZOJ 2157 旅行(树链剖分码农题)
写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
- BZOJ 3083 遥远的国度 树链剖分+线段树
有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...
- BZOJ 2243 染色 树链剖分
题意: 给出一棵树,每个顶点上有个颜色\(c_i\). 有两种操作: C a b c 将\(a \to b\)的路径所有顶点上的颜色变为c Q a b 查询\(a \to b\)的路径上的颜色段数,连 ...
- BZOJ 3626 离线+树链剖分+线段树
思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
随机推荐
- Android 体系结构介绍
转自:http://blog.sina.com.cn/s/blog_4bc996c40100fawo.html 第一.操作系统层(OS)第二.各种库(Libraries)和Android 运行环境(R ...
- loj 101 最大流
冬令营送到我脸上的20分都没拿全 心态爆炸 冬令营前一天学的dinic 后一天才发出来 #include<iostream> #include<cstdio> #include ...
- bzoj3112
http://www.lydsy.com/JudgeOnline/problem.php?id=3112 模板题...模板又打错了... #include<bits/stdc++.h> u ...
- vue单页面应用刷新网页后vuex的state数据丢失问题以及beforeunload的兼容性
最近在用vue写h5项目,当使用window.location重定向页面或者刷新当前页面时, 发现当刷新网页后,保存在vuex实例store里的数据会丢失. 后来在网上查找大神的解决方案如下: exp ...
- Linux命令补充及基础优化。
1.用户部分 1.1 创建新用户 涉及命令 useradd [root@oldboyedu-50 ~]# useradd oldboy #添加用户 oldboy 1.2 设置密码 [root@oldb ...
- Java中的管道流 PipedOutputStream和PipedInputStream
我们在学习IO流的时候可能会学字节流.字符流等,但是关于管道流的相信大部分视频或者教程都是一语带过,第一个是因为这个东西在实际开发中用的也不是很多,但是学习无止境,存在既有理.JDK中既然有个类那说明 ...
- Linux 本命令 基本上用到的命令-自己留着用
1:在某个目录下查找文件: find /data -name '*srm*' 2:监测文件流: tail –f /data/log.xml 3: 删除文件: rm –f /data/log.xm ...
- Sorting It All Out 拓扑排序+确定点
这一道题的话 数据有一点问题 ........ 例如 不过 还是 能理解一下 试试吧 ......... A<B B<C C<A A<C B<A ...
- ACM_夏天到了,又到了出游的季节
夏天到了,又到了出游的季节 Time Limit: 2000/1000ms (Java/Others) Problem Description: QWER最近无心打代码,于是带着n套衣服出去浪.但是每 ...
- 设计模式 Singleton 单例 懒汉,线程安全
首先来明确一个问题,那就是在某些情况下,有些对象,我们只需要一个就可以了, 比如,一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个, 这里就可以通过单例模式来避免两个打印作业同时输 ...