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 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
随机推荐
- 利用POI抽取word中的图片并保存在文件中
利用POI抽取word中的图片并保存在文件中 poi.apache.org/hwpf/quick-guide.html 1.抽取word doc中的图片 package parse; import j ...
- [Codeforces Round495A] Sonya and Hotels
[题目链接] https://codeforces.com/contest/1004/problem/A [算法] 直接按题意模拟即可 时间复杂度 :O(NlogN) [代码] #include< ...
- 用回调函数创建一个XMLHttpRequest,并从一个TXT文件中检索数据。
<script> var xmlhttp; function loadXMLDoc(url,soyo) { if (window.XMLHttpRequest) {// IE7+, Fir ...
- Android之NDK开发(转载)
http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html 一.NDK产生的背景 Android平台从诞生起,就已经支持C.C+ ...
- PCB 录屏工具Screen2Exe GifCam ScreenToGif
我们完成的软件作品后,需要向客户或领导演示软件功能介绍,这里力推3款录屏工具 一.Screen2Exe工具,录制exe视频文件 下载地址 http://pcbren.cn/ShareFiles/Sc ...
- js返回上一层
Javascript 返回上一页 1. Javascript 返回上一页 history.go(-1), 返回两个页面: history.go(-2); 2. history.back(). wind ...
- POJ3687Labeling Balls
Labeling Balls Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14278 Accepted: 4162 D ...
- [Swift通天遁地]五、高级扩展-(4)快速生成Invert、Mix、Tint、Shade颜色及调整饱和度阶
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- HTML--使用下拉列表框进行多选
下拉列表也可以进行多选操作,在<select>标签中设置multiple="multiple"属性,就可以实现多选功能,在 widows 操作系统下,进行多选时按下Ct ...
- Android源码下载方法
1. 下载 repo 工具 mkdir ~/bin PATH=~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/re ...