3730: 震波

Time Limit: 15 Sec  Memory Limit: 256 MB
Submit: 626  Solved: 149
[Submit][Status][Discuss]

Description

在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。

Input

第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。

Output

包含若干行,对于每个询问输出一行一个正整数表示答案。

Sample Input

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

Sample Output

11100101

HINT

1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1

Source

Solution

动态点分治裸题...

动态点分治就是将点分治中的重心形成的树形结构(点分树)利用起来,每层维护对答案的贡献,然后暴力求解。

静态的点分治问题常见的有两种统计答案的方法,一种是处理一棵子树,统计当前子树与之前子树共同对答案的贡献,然后将当前子树的贡献加入,重复处理下一棵子树。

另一种方法就是先处理出所有子树对答案的贡献,然后每棵子树与其他子树共同对答案的贡献就是,当前子树+(总-当前子树)。表述有限反正就是那么个意思...

动态点分治维护的信息只适用于第二种方式的信息。

考虑这种方法的时空复杂度。因为点分树树高严格$logN$,如果每层统计答案复杂度$logN$,暴力爬树查询修改的复杂度是$log^{2}N$的,空间复杂度动态存储也是$log^{2}N$。

不仅支持修改和查询,同时可以支持加叶子操作,因为加叶子操作不会直接影响重心,但是会引起最初构造的点分树不平衡,复杂度无法得到保证,所以可以利用替罪羊树的思想,定期进行重建。

对于这道题,询问距离点距离小于等于$K$的点权和,支持修改。

建出点分树,考虑每个点维护两个树状数组$f,g$,分别表示 距离该点距离为$k$的点权和 距离该点点分树上父亲的距离为$k$的点权和 ,距离为下标,额外进行一遍dfs即可预处理得到。

查询,从查询点开始沿着点分树向上爬,按照做差去重的方式统计答案,修改同理。

显然树状数组要动态内存,所以要vector....谢谢Yveh大爷对萌新的指导QwQ

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{int x=0,f=1; char ch=getchar();while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}return x*f;
}
#define MAXN 100010
int N,M,val[MAXN],lastans;namespace Tree{struct EdgeNode{int next,to;}edge[MAXN<<1];int head[MAXN],cnt=1;inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}int deep[MAXN],dist[MAXN],father[18][MAXN];inline void DFS(int now,int last){for (int i=1; i<=17; i++)if (deep[now]>=(1<<i))father[i][now]=father[i-1][father[i-1][now]];elsebreak;for (int i=head[now]; i; i=edge[i].next)if (edge[i].to!=last) {deep[edge[i].to]=deep[now]+1;dist[edge[i].to]=dist[now]+1;father[0][edge[i].to]=now;DFS(edge[i].to,now);}}inline int LCA(int x,int y){if (deep[x]<deep[y]) swap(x,y);int dd=deep[x]-deep[y];for (int i=0; i<=17; i++)if (dd&(1<<i)) x=father[i][x];for (int i=17; i>=0; i--)if (father[i][x]!=father[i][y])x=father[i][x],y=father[i][y];return x==y? x:father[0][x];}inline int Dist(int x,int y) {int z=LCA(x,y);return deep[x]+deep[y]-deep[z]-deep[z];}
}using namespace Tree;namespace BIT{typedef vector<int> vec;struct BIT{vec tree; int n; inline void init(int size) {tree.resize(size+2); n=size+1;}inline int lowbit(int x) {return x&-x;}inline void Modify(int x,int d) {if (x<=0) return; for (int i=x; i<=n; i+=lowbit(i)) tree[i]+=d;}inline int Query(int x) {int re=0; if (x>n) x=n; for (int i=x; i>0; i-=lowbit(i)) re+=tree[i]; return re;}}f[MAXN],g[MAXN];
}using namespace BIT;namespace TreeDivide{int size[MAXN],mx[MAXN],root,Sz,par[MAXN];bool visit[MAXN];inline void Getroot(int now,int last){size[now]=1,mx[now]=0;for (int i=head[now]; i; i=edge[i].next)if (edge[i].to!=last && !visit[edge[i].to]) {Getroot(edge[i].to,now);size[now]+=size[edge[i].to];mx[now]=max(mx[now],size[edge[i].to]);}mx[now]=max(mx[now],Sz-size[now]);if (mx[now]<mx[root]) root=now;}inline void DFS(int now,int last,int dep){f[root].Modify(dep+1,val[now]);g[par[root]].Modify(dep+1,val[now]);for (int i=head[now]; i; i=edge[i].next)if (edge[i].to!=last && !visit[edge[i].to]) {DFS(edge[i].to,now,dep+1);}}inline void Divide(int now){
//      printf("Divide = %d\n",now);visit[now]=1;g[now].Modify(1,val[now]);for (int i=head[now]; i; i=edge[i].next)if (!visit[edge[i].to]) {root=0;Sz=size[edge[i].to];Getroot(edge[i].to,now);par[root]=now;f[root].init(Sz),g[root].init(Sz);DFS(edge[i].to,now,1);Divide(root);}}inline void Modify(int x,int y){for (int i=x; i; i=par[i]) {int dep=Tree::Dist(x,i)+1;g[i].Modify(dep,y-val[x]);if (par[i])dep=Tree::Dist(par[i],x)+1,f[i].Modify(dep,y-val[x]);}val[x]=y;}inline int Query(int x,int k){int ans=0;for (int i=x; i; i=par[i]) {int dep=k-Tree::Dist(x,i)+1;ans+=g[i].Query(dep);if (par[i])dep=k-Tree::Dist(x,par[i])+1,ans-=f[i].Query(dep);}return ans;}
}using namespace TreeDivide;int main()
{N=read(),M=read();for (int i=1; i<=N; i++) val[i]=read();for (int i=1,x,y; i<=N-1; i++) x=read(),y=read(),Tree::InsertEdge(x,y);Tree::DFS(1,0);Sz=mx[root=0]=N;Getroot(1,0);f[root].init(Sz),g[root].init(Sz); Divide(root);while (M--) {int opt=read(),x=read(),y=read();x^=lastans,y^=lastans;if (opt==1) {TreeDivide::Modify(x,y);} else {printf("%d\n",lastans=TreeDivide::Query(x,y));}}return 0;
}

  

转载于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6352238.html

【BZOJ-3730】震波 动态点分治 + 树状数组相关推荐

  1. bzoj 3730: 震波 动态点分治+树链剖分+线段树

    ##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随 ...

  2. Bzoj 3730 震波 动态点分治

    Bzoj 3730 震波 题解: 和在线的边分治差不多. 就是将每层都信息都存下来. 然后对于每一层记录上一层的重心是哪个. 对于求和的话, 从自己的那层出发,然后暴力往上爬, 然后计算答案. 对于修 ...

  3. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  4. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  5. BZOJ.3648.寝室管理(点分治 树状数组)

    BZOJ \(Description\) 求在一棵树上加一条边后,有多少条至少有\(k\)个点的路径. \(n\leq10^5\). \(Solution\) 对于一棵树的情况,可以点分治. 用树状数 ...

  6. BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )

    考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...

  7. BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)

    BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...

  8. P4093-[HEOI2016/TJOI2016]序列【CDQ分治,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P4093 题目大意 nnn个数字,每次有一个数字可能和原序列不同,但最多只有一个不同. 求所有情况下都满足的最长不降 ...

  9. P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P3157 题目大意 一个长度为nnn序列,每次删除一个数,求删除前的逆序对数量. 解题思路 时光倒流之后,我们变为每 ...

最新文章

  1. 在不允许新建对象的条件下,将list中指定条件的值去除
  2. 【教程】Python数据可视化技巧
  3. 浅谈jsp的7个动作
  4. GPU — 物理 GPU 虚拟化技术
  5. mp4格式解析、分割
  6. 将图形以PNG格式输出到浏览器或文件
  7. maven使用testng_使用ReportNG更好看的TestNG HTML测试报告– Maven指南
  8. 实例10:python
  9. IOC操作Bean管理XML方式(外部属性文件)
  10. mysql 日期型中文报错_mysql日期类型默认值'0000-00-00' 报错,是什么问题?
  11. vue添加html开启服务器_Vue 项目(HTML5 History 模式) 部署服务器
  12. 【NOI2002】银河英雄传说
  13. Web — 调色盘打开+div
  14. 以太坊 智能合约IDE 在线 Solidity IDE
  15. 如何刷原生android系统版本,小米手机1原生Android4.1系统刷机教程
  16. lwj_C#_周总结2 字符串练习
  17. 安徽大学计算机考研经验贴
  18. IP 地址 与硬件地址
  19. InfluxDB使用HTTP的API编写数据
  20. js中数组的entries方法

热门文章

  1. asp.net学习之再论sqlDataSource 2
  2. 漫步线性代数二十四——行列式应用
  3. 信号处理:单边、双边频谱间的相互转换(转)
  4. simulink 分析达芬方程
  5. Photoshop cs6中kuler和mini bridge打开是空白的解决方法
  6. HTTP协议入门——1.1版本
  7. 【实践驱动开发2-001】wifi 在android 下的实现 - AR6000 系列移植详细步骤
  8. php正则去掉width=,关于php使用正则去除宽高样式的方法
  9. localhost可以访问 ip不能访问_为啥用 ip 不可以访问知乎,而百度却可以?
  10. html中高与行高的区别,CSS中line-height与height有什么区别