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次操作。
输出
包含若干行,对于每个询问输出一行一个正整数表示答案。
样例输入
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
样例输出
提示
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
我们考虑单次询问用点分治如何处理?假设查询点为x。
1、如果当前分治联通块中没有x,那么不用再分治统计了;
2、如果当前联通块中有x并且x不是分治中心,假设当前分治中心与x间的距离为d,我们需要找到与分治中心距离<=k-d的所有点的点权和。但这样统计有不合法的点,即与x在分治中心的同一棵子树中的点,所有我们还需要统计x所在的分治中心的那棵子树中与分治中心距离<=k-d的所有点权和,将这部分答案减掉即可。
3、如果x为当前分治中心,那么直接统计当前联通块中与x距离<=k的点的点权和即可。
其实第三种情况可以归为第二种情况中,那么我们就可以得出每个点需要维护的信息(其中k为任意距离,为了方便我们称以一个点为分治中心时能遍历到的点组成的联通块为这个点管辖的联通块):
1、以当前点为分治中心时联通块中与这个点距离<=k的点权和,这个用线段树维护每个距离的点权和即可。
2、以当前点在原树上的父节点为分治中心时,这个点在原树的子树中与这个点父节点距离<=k的点权和,这个同样用线段树维护,但是我们知道当前点在点分树上无法维护这个联通块的信息,所以这个联通块的信息由这个联通块的重心的那棵线段树来维护。也就变成了每个点维护点分树上这个点子树中所有点与这个点在点分树上的父节点距离<=k的点的点权和。
那么修改就很好办了,因为一个点的点权只被这个点在点分树上到根路径上所有点保存,只要暴力往根爬然后修改沿途节点线段树中信息即可。
对于查询,因为我们只需要知道管辖的联通块中包含查询点的点的信息即可,而这些点就是查询点在点分树上到根路径上的所有点,我们依旧暴力往根爬并统计沿途点的答案即可。
时间复杂度O(nlogn^2)
这个题很卡常,对于每个点要求出以它为分治中心时联通块中的最大深度作为这个点维护的线段树的上界,这样能减少递归层数。并且线段树数组要用结构体存,还要加读入优化……
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
inline char _read()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,f=1;char ch=_read();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
return x*f;
}
int n,m;
int tot;
int num;
int cnt;
int dfn;
int opt;
int x,y;
int ans;
int rot;
int res;
int mxp;
int f[100010];
int s[100010];
int d[100010];
int mn[100010];
int lg[200010];
int to[200010];
int mx[100010];
int dep[100010];
int val[100010];
int vis[100010];
int next[200010];
int head[100010];
int size[100010];
int root[100010];
int froot[100010];
int g[18][200010];
struct miku
{
int ls,rs,sum;
}tr[9000000];
inline void add(int x,int y)
{
next[++tot]=head[x],head[x]=tot,to[tot]=y;
}
void dfs(int x,int fa)
{
g[0][++dfn]=dep[x];
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
dfs(to[i],x);
g[0][++dfn]=dep[x];
}
}
}
inline void getroot(int x,int fa)
{
mx[x]=0;
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
void find_dep(int x,int fa)
{
d[x]=d[fa]+1;
mxp=max(mxp,d[x]);
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
find_dep(to[i],x);
}
}
}
inline void partation(int x)
{
vis[x]=1;
mxp=0;
find_dep(x,0);
mn[x]=mxp;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
rot=0;
getroot(to[i],0);
f[rot]=x;
partation(rot);
}
}
}
inline int lca(int x,int y)
{
x=s[x];
y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return min(g[len][x],g[len][y-(1<<len)+1]);
}
inline int dis(int x,int y)
{
return dep[x]+dep[y]-(lca(x,y)<<1);
}
inline void insert(int &rt,int l,int r,int k,int x)
{
if(!rt)
{
rt=++cnt;
}
tr[rt].sum+=x;
if(l==r)
{
return ;
}
if(k<=mid)
{
insert(tr[rt].ls,l,mid,k,x);
}
else
{
insert(tr[rt].rs,mid+1,r,k,x);
}
}
inline int query(int rt,int l,int r,int k)
{
if(!rt)
{
return 0;
}
if(l==r)
{
return tr[rt].sum;
}
if(k<=mid)
{
return query(tr[rt].ls,l,mid,k);
}
else
{
return tr[tr[rt].ls].sum+query(tr[rt].rs,mid+1,r,k);
}
}
inline void change(int x,int val)
{
for(int i=x;i;i=f[i])
{
insert(root[i],0,mn[i],dis(x,i),val);
if(f[i])
{
insert(froot[i],0,mn[f[i]],dis(x,f[i]),val);
}
}
}
inline int query(int x,int k)
{
res=0;
for(int i=x;i;i=f[i])
{
if(dis(x,i)<=k)
{
res+=query(root[i],0,mn[i],k-dis(x,i));
}
if(f[i]&&dis(x,f[i])<=k)
{
res-=query(froot[i],0,mn[f[i]],k-dis(x,f[i]));
}
}
return res;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
val[i]=read();
}
for(int i=1;i<n;i++)
{
x=read();
y=read();
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;(1<<j)<=dfn;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
g[j][i]=min(g[j-1][i],g[j-1][i+(1<<(j-1))]);
}
}
mx[0]=1<<30;
num=n;
getroot(1,0);
partation(rot);
for(int now=1;now<=n;now++)
{
for(int i=now;i;i=f[i])
{
insert(root[i],0,mn[i],dis(now,i),val[now]);
if(f[i])
{
insert(froot[i],0,mn[f[i]],dis(now,f[i]),val[now]);
}
}
}
while(m--)
{
opt=read();
x=read()^ans;
y=read()^ans;
if(!opt)
{
printf("%d\n",ans=query(x,y));
}
else
{
change(x,y-val[x]);
val[x]=y;
}
}
}
BZOJ3730震波——动态点分治+线段树(点分树套线段树)的更多相关文章
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
- BZOJ3730 震波 | 动态点分治
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...
- 【bzoj3730】震波 动态点分治+线段树
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- 【BZOJ-3730】震波 动态点分治 + 树状数组
3730: 震波 Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 626 Solved: 149[Submit][Status][Discuss] D ...
- bzoj 3730: 震波 动态点分治_树链剖分_线段树
##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着 ...
- 【BZOJ3730】震波 - 动态点分治
题意: Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震, ...
- [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...
- BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- bzoj 3730 震波 (动态点分治)
大意: 给定n节点树, 每个节点有权值, 边权全为1. 给定m个操作: 操作1: (0,x,k) 表示询问到节点x距离不超过k的节点权值和 操作2: (1,x,y) 表示将节点x的权值修改为y 对于所 ...
随机推荐
- Java之所有输入流输出流的分类
(1)字节输入流 基类:InputStream FileInputStream.ByteArrayInputStream.PipedInputStream.Buffered ...
- centos 7 java1.8安装
java安装 检查版本信息,如果版本小于1.8,执行以下命令 java -version java version "1.8.0_144"Java(TM) SE Runtime E ...
- nrf2401 - 最廉价的2.4G无线通信方案
所有的使用Arduino 的朋友大多都会知道大名鼎鼎的XBee 这个土豪级的ZigBee 的通信模块.我们是做产品开发的,对于XBee这个产品可谓是又爱又恨,不得不承认他确实是一个好货,从做工到功能都 ...
- 使用go mod结合docker分层缓存进行自动CI/CD
本文地址:https://www.cnblogs.com/likeli/p/10521941.html 喜大奔的go mod 官方背书的go mod拯救了我的代码洁癖症! 环境 go v1.12 do ...
- H5 28-优先级之权重问题
28-优先级之权重问题 我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
- 逻辑回归为什么用sigmoid函数
Logistic回归目的是从特征学习出一个0/1分类模型,而这个模型是将特性的线性组合作为自变量,由于自变量的取值范围是负无穷到正无穷. 因此,使用logistic函数(或称作sigmoid函数)将自 ...
- MySQL数据类型--日期和时间类型
MySQL中的多种时间和格式数据类型 日期和时间类型是为了方便在数据库中存储日期和时间而设计的.MySQL中有多种表示日期和时间的数据类型. 其中,year类型表示时间,date类型表示日期,time ...
- 如何优化Docker储存
大家在使用Docker的过程中,有没有想过,Docker在本地存储镜像时把文件存储在哪里了呢?有没有对文件的总大小做一定的限制呢?能不能调整本地存储的位置及总限制大小呢?今天,我们就从这些问题入手,来 ...
- 在java中怎样获得当前日期时间
Calendar cal = Calendar.getInstance(); java.text.SimpleDateFormat sdf = new SimpleDateFormat(&quo ...
- 【问题解决方案】之 Word 公式编辑器 使用小tips
输入空格:shift+Ctrl+space 换行:直接回车.之后在上方菜单栏中选择"在等号处对齐"