【bzoj3730】震波 动态点分治+线段树
题目描述
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
输入
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
输出
包含若干行,对于每个询问输出一行一个正整数表示答案。
样例输入
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
样例输出
11100101
题解
动态点分治+线段树
考虑点分树的某一层除了查询点对应子树的部分,它们到查询点的路径都是:该点-该层节点-查询点。
因此求出该层节点到查询点的距离,就知道了该点到该层节点的距离的范围。
于是可以对于每一个节点按照距离维护一棵线段树,表示该节点点分树子树内到其距离为某值的所有节点的权值和。
一个问题:如何表示点分树除了查询点子树的部分?
静态点分治提供了一个很好的方法:容斥。
因此还要对每个节点维护另一颗线段树,表示该节点点分树子树内到其父亲节点距离为某值的所有节点的权值和。查询时减一下即可。
另一个问题:如何快速求出两点间距离?使用RMQLCA,预处理后 $O(1)$ 查询LCA深度即可。
时间复杂度 $O(n\log^2n)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define lson l , mid , ls[x]
#define rson mid + 1 , r , rs[x]
using namespace std;
int n , head[N] , to[N << 1] , next[N << 1] , cnt , deep[N] , pos[N] , md[20][N << 1] , log[N << 1] , tot;
int v[N] , vis[N] , si[N] , ms[N] , ts , root , fa[N] , ra[N] , rb[N];
int ls[N * 200] , rs[N * 200] , sum[N * 200] , tp;
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int last)
{
int i;
pos[x] = ++tot , md[0][tot] = deep[x];
for(i = head[x] ; i ; i = next[i])
if(to[i] != last)
deep[to[i]] = deep[x] + 1 , dfs(to[i] , x) , md[0][++tot] = deep[x];
}
inline int dis(int x , int y)
{
int t = deep[x] + deep[y] , k;
x = pos[x] , y = pos[y];
if(x > y) swap(x , y);
k = log[y - x + 1];
return t - (min(md[k][x] , md[k][y - (1 << k) + 1]) << 1);
}
void update(int p , int a , int l , int r , int &x)
{
if(!x) x = ++tp;
sum[x] += a;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , a , lson);
else update(p , a , rson);
}
int query(int p , int l , int r , int x)
{
if(!x) return 0;
if(l == r) return sum[x];
int mid = (l + r) >> 1;
if(p <= mid) return query(p , lson);
else return query(p , rson) + sum[ls[x]];
}
void getroot(int x , int last)
{
int i;
si[x] = 1 , ms[x] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != last)
getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
ms[x] = max(ms[x] , ts - si[x]);
if(ms[x] < ms[root]) root = x;
}
void deal(int x , int last , int p)
{
update(dis(x , p) , v[x] , 0 , n - 1 , ra[p]);
if(fa[p]) update(dis(x , fa[p]) , v[x] , 0 , n - 1 , rb[p]);
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != last)
deal(to[i] , x , p) , si[x] += si[to[i]];
}
void work(int x)
{
int i;
deal(x , 0 , x) , vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]])
root = 0 , ts = si[to[i]] , getroot(to[i] , 0) , fa[root] = x , work(root);
}
inline void modify(int x , int y)
{
int i;
for(i = x ; i ; i = fa[i])
{
update(dis(x , i) , y - v[x] , 0 , n - 1 , ra[i]);
if(fa[i]) update(dis(x , fa[i]) , y - v[x] , 0 , n - 1 , rb[i]);
}
v[x] = y;
}
inline int solve(int x , int k)
{
int i , ans = 0;
for(i = x ; i ; i = fa[i])
{
if(dis(x , i) <= k) ans += query(k - dis(x , i) , 0 , n - 1 , ra[i]);
if(fa[i] && dis(x , fa[i]) <= k) ans -= query(k - dis(x , fa[i]) , 0 , n - 1 , rb[i]);
}
return ans;
}
int main()
{
int m , i , j , opt , x , y , last = 0;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
dfs(1 , 0);
for(i = 2 ; i <= tot ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = 1 ; (1 << i) <= tot ; i ++ )
for(j = 1 ; j <= tot - (1 << i) + 1 ; j ++ )
md[i][j] = min(md[i - 1][j] , md[i - 1][j + (1 << (i - 1))]);
ms[0] = 1 << 30 , ts = n , getroot(1 , 0) , work(root);
while(m -- )
{
scanf("%d%d%d" , &opt , &x , &y) , x ^= last , y ^= last;
if(!opt) printf("%d\n" , last = solve(x , y));
else modify(x , y);
}
return 0;
}
【bzoj3730】震波 动态点分治+线段树的更多相关文章
- BZOJ3730震波——动态点分治+线段树(点分树套线段树)
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
- BZOJ 4372/3370 烁烁的游戏/震波 (动态点分治+线段树)
烁烁的游戏 题目大意: 给你一棵$n$个节点的树,有$m$次操作,询问某个节点的权值,或者将与某个点$x$距离不超过$d$的所有节点的权值都增加$w$ 动态点分裸题 每个节点开一棵权值线段树 对于修改 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树
题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...
- bzoj 3730: 震波 动态点分治_树链剖分_线段树
##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着 ...
随机推荐
- 20155325实验四 Android程序设计
实验四 Android程序设计-1 Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)&g ...
- echarts 柱状图移除圆角
itemStyle: { normal: { color: '#59519f', barBorderColor: '#59519f', barBorderWidth: 6, barBorderRadi ...
- 杂谈001:晨曦Dawn的重新连接
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 摘要: 我是晨曦,好久没有关注过我的博客了,整天都在乱糟糟的忙,叙述一下我消失的这段时间,然后我准备做几个专题 ...
- 远程连接ejabberd的mnesia数据库
由于服务器是server版本,所以很难直观的看到mnesia的数据.所以对于初学者来说非常的困惑. 特地在qq群中请教了别人.别人说只要pong通了就行,就能通过rpc去操作远程的mnesia数据库. ...
- Struts 2(八):文件上传
第一节 基于Struts 2完成文件上传 Struts 2框架中没有提供文件上传,而是通过Common-FileUpload框架或COS框架来实现的,Struts 2在原有上传框架的基础上进行了进一步 ...
- linux下汇编语言开发总结
汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影.但是这并不表示汇编语言就已经没有 ...
- Eclipse 无法编译 或 提示“错误: 找不到或无法加载主类”
project显示一个红色叹号,通常是.jar文件缺失,在下面找到配置 在libraries中添加add External JARs添加.jar文件
- 转发——谷歌云官方:一小时掌握深度学习和 TensorFlow
转发——谷歌云官方:一小时掌握深度学习和 TensorFlow 本文转发自新智元,链接如下: http://mp.weixin.qq.com/s?__biz=MzI3MTA0MTk1MA==& ...
- PReLU——Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification
1. 摘要 在 \(ReLU\) 的基础上作者提出了 \(PReLU\),在几乎没有增加额外参数的前提下既可以提升模型的拟合能力,又能减小过拟合风险. 针对 \(ReLU/PReLU\) 的矫正非线性 ...
- 【RL系列】马尔可夫决策过程——Gambler's Problem
Gambler's Problem,即“赌徒问题”,是一个经典的动态编程里值迭代应用的问题. 在一个掷硬币游戏中,赌徒先下注,如果硬币为正面,赌徒赢回双倍,若是反面,则输掉赌注.赌徒给自己定了一个目标 ...