[bzoj3730] 震波

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

Solution

点分树套树状数组。

先建出点分树,对于每个分治块建一颗树状数组;对于每个分治块的重心,每个儿子的子树也建一颗树状数组。

树状数组以\(dep\)为下标,记的是权值之和。

那么对于修改点权,一共有\(O(\log n)\)个分治块和它相交,在树状数组上修改下就好了。

对于询问也差不多,暴力枚举每个分治块,答案加上树状数组上的值,在减去\(x\)所在的那颗子树的贡献即可。

具体的,对于每个点,开个\(vector\)记录一些四元组,表示分治重心,所在的儿子子树的儿子的编号,到分治重心的距离,以及重心的儿子的树状数组的编号。

然后大力出奇迹,多\(dfs\)几遍就做完了。

注意树状数组需要动态开点,可以对于每个树状数组算出一个最大可以访问到的\(dep\),然后动态分配内存,这个小\(trick\)具体可以看代码,树状数组的\(build\)部分。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;

int n,m,val[maxn],tot,head[maxn];

struct edge{int to,nxt;}e[maxn<<1];

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

int space[maxn*100],pos,cnt;

struct Binary_Indexed_Tree {
	int len,*t;
	void build(int l) {len=l,t=space+pos+2,pos+=l+4;}
	void modify(int x,int v) {for(int i=x;i<=len;i+=i&-i) t[i]+=v;}
	int query(int x,int ans=0) {
		if(x<=0) return 0;x=min(x,len);
		for(int i=x;i;i-=i&-i) ans+=t[i];return ans;
	}
}bit[maxn];

int rt,sz[maxn],f[maxn],vis[maxn],siz,mxdep[maxn],dep[maxn],h[maxn];

struct data {int x,y,dis,bel;};

vector<data > s[maxn];

map<int,int > r[maxn];

void get_rt(int x,int fa) {
	sz[x]=1,f[x]=0;
	for(int i=head[x];i;i=e[i].nxt)
		if(!vis[e[i].to]&&e[i].to!=fa) 
			get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
	f[x]=max(f[x],siz-sz[x]);
	if(f[rt]>f[x]) rt=x;
}

void get_mxdep(int x,int fa) {
	dep[x]=dep[fa]+1,mxdep[x]=dep[x];
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa&&!vis[e[i].to]) {
			get_mxdep(e[i].to,x);
			mxdep[x]=max(mxdep[x],mxdep[e[i].to]);
		}
}

int de,de2;

void make(int x,int fa) {
	bit[cnt].modify(dep[x],val[x]);
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa&&!vis[e[i].to]) make(e[i].to,x);
}

void mark(int x,int fa,int a,int y,int d,int b) {
	s[x].push_back((data){a,y,d,b});
	for(int i=head[x];i;i=e[i].nxt)
		if(!vis[e[i].to]&&e[i].to!=fa) mark(e[i].to,x,a,y,d+1,b);
}

void build(int x) {
	get_mxdep(x,0);
	cnt++;h[x]=cnt;
	bit[cnt].build(mxdep[x]);
	de=x;make(x,0);
	for(int i=head[x];i;i=e[i].nxt)
		if(!vis[e[i].to]) {
			dep[x]=0;get_mxdep(e[i].to,x);cnt++;
			bit[cnt].build(mxdep[e[i].to]+1);
			de=0;make(e[i].to,x);
			mark(e[i].to,x,x,e[i].to,1,cnt);
		}
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
		if(!vis[e[i].to]) {
			get_rt(e[i].to,0),siz=sz[e[i].to],rt=0;
			get_rt(e[i].to,0),build(rt);
		}
}

void change(int x,int y) {
	vector<data > :: iterator it;
	for(it=s[x].begin();it!=s[x].end();it++) {
		data da=*it;
		bit[h[da.x]].modify(da.dis+1,y-val[x]);
		bit[da.bel].modify(da.dis,y-val[x]);
	}
	bit[h[x]].modify(1,y-val[x]);
	val[x]=y;
}

int query(int x,int y) {
	int ans=0;
	vector<data > :: iterator it;
	for(it=s[x].begin();it!=s[x].end();it++) {
		data da=*it;
		ans+=bit[h[da.x]].query(y-da.dis+1);
		ans-=bit[da.bel].query(y-da.dis);
	}
	ans+=bit[h[x]].query(y+1);
	return ans;
}

int main() {
	read(n),read(m);
	for(int i=1;i<=n;i++) read(val[i]);
	for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y);
	siz=n,f[0]=maxn,get_rt(1,0),build(rt);
	int lstans=0;
	for(int i=1;i<=m;i++) {
		int op,x,y;read(op),read(x),read(y);
		x^=lstans,y^=lstans;
		if(op==1) change(x,y);
		else write(lstans=query(x,y));
	}
	return 0;
}
posted @ 2019-01-13 20:32  Hyscere  阅读(165)  评论(0编辑  收藏  举报