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 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
随机推荐
- 使用EL表达式正确情况下报错:javax.servlet.jsp cannot be resolved to a type
这个错误可能是服务器自带的servlet库未导入的原因.右键项目属性,转到Targeted Runtimes,选择一个服务器,例如Tomcat,单击应用,可能就可以解决.
- PCB SQL SERVER 正则应用实例
我们用过SQL SERVER的都知道,SQL SERVER它本身是不自带正则表达式的,因为没有,所以基本都没用过啊, 但我们在C#中对文本匹配用正则的方式处理非常好用,省得你写一堆代码实现匹配,多简洁 ...
- Linux命令补充及基础优化。
1.用户部分 1.1 创建新用户 涉及命令 useradd [root@oldboyedu-50 ~]# useradd oldboy #添加用户 oldboy 1.2 设置密码 [root@oldb ...
- [Swift通天遁地]五、高级扩展-(2)扩展集合类型
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- BZOJ 4481
思路: 等比数列求和 (无穷项) +线段树找逆序对 //By SiriusRen #include <bits/stdc++.h> ; ; ],ans; struct Node{int x ...
- 【洛谷4219】[BJOI2014]大融合(线段树分治)
题目: 洛谷4219 分析: 很明显,查询的是删掉某条边后两端点所在连通块大小的乘积. 有加边和删边,想到LCT.但是我不会用LCT查连通块大小啊.果断弃了 有加边和删边,还跟连通性有关,于是开始yy ...
- 【洛谷2904/BZOJ1617】[USACO08MAR]跨河River Crossing(动态规划)
题目:洛谷2904 分析: 裸dp-- dp方程也不难想: \(dp[i]\)表示运\(i\)头牛需要的最短时间,\(sum[i]\)表示一次运\(i\)头牛(往返)所需的时间,则 \[dp[i]=m ...
- SCOI2014总结
似乎还没有写过SCOI的总结,今天补上,权当填坑. PS:CDQZ的看到了不要到处黑 SCOI-2014应该算是我的小高考,感觉拿住一本招的瓶颈就在这里.加之NOIp只有400分有点拖后腿,所以很早就 ...
- 【转】Linux GCC常用命令
转自:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html 1简介 2简单编译 2.1预处理 2.2编译为汇编代码(Comp ...
- 整合springboot,angular2,可以前后台交互数据
改造了一下angular2官方文档中的hero项目,让其可以进行后台的交互, https://github.com/DACHUYIN 源码在上面...博客就不写了....