[BZOJ3730][點分樹]震波

鏈接自己找,BZOJ還沒開

也很顯然是點分樹維護,對每個點開兩個樹狀數組,維護點分樹上子樹之和,然後修改詢問仍然暴力爬樹,詢問也是用兩個樹狀數組作差消掉當前子樹影響

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1e5+5,INF=1e9;
struct Heap{
	priority_queue<int>a,del;
	inline void push(int x){a.push(x);}
	inline void erase(int x){del.push(x);}
	inline void pop(){
		while(del.size() && del.top()==a.top()) del.pop(),a.pop();
		if(!a.empty()) a.pop();
	}
	inline int top(){
		while(del.size() && del.top()==a.top()) del.pop(),a.pop();
		if(a.empty()) return 0;
		return a.top();	
	}
	inline int size(){return a.size()-del.size();}
	inline int second(){
		if(size()<2) return 0;
		int x=top();pop();
		int y=top();push(x);
		return y;
	}
}ans,now[N],up[N];
int vis[N<<1],head[N],nxt[N<<1],tot=0;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
int dp[N],fa[N][20],siz[N],pt[N];
int sum,rt;
void getroot(int v,int f){
	siz[v]=1;dp[v]=0;
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(y==f || pt[y]) continue;
		getroot(y,v);
		siz[v]+=siz[y];
		dp[v]=max(dp[v],siz[y]);
	}
	dp[v]=max(dp[v],sum-siz[v]);
	if(dp[v]<dp[rt]) rt=v;
}
vector<int>tr1[N],tr2[N];
int d[N],dis[N][20];
void getship(int v,int anc,int f,int dd){
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(pt[y] || y==f) continue;
		fa[y][++d[y]]=anc;
		dis[y][d[y]]=dd;
		getship(y,anc,v,dd+1);
	}
}
void buildtree(int v){
	pt[v]=1;getship(v,v,0,1);
	int all=sum;
	tr1[v].resize(all+1);tr2[v].resize(all+1);
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(pt[y]) continue;
		sum=siz[y];if(sum>siz[v]) sum=all-siz[v];
		rt=0;getroot(y,v);buildtree(rt);
	}
}
inline int lb(int x){return x&(-x);}
int val[N];
inline int qsum1(int x,int y){
	int res=val[x],n=tr1[x].size()-1;y=min(y,n);
	for(int i=y;i;i-=lb(i)) res+=tr1[x][i];
	return res;
}
inline int qsum2(int x,int y){
	int res=0,n=tr2[x].size()-1;y=min(y,n);
	for(int i=y;i;i-=lb(i)) res+=tr2[x][i];
	return res;
}
inline int query(int x,int k){
	int res=qsum1(x,k);
	for(int i=d[x];i;i--) if(dis[x][i]<=k) res+=qsum1(fa[x][i],k-dis[x][i])-qsum2(fa[x][i+1],k-dis[x][i]);
	return res;
}
inline void change(int x,int v){
	int pos,n;
	pos=dis[x][d[x]];n=tr1[x].size()-1;
	for(int i=pos;i<=n && i;i+=lb(i)) tr2[x][i]+=v;
	for(int i=d[x];i;i--){
		pos=dis[x][i];n=tr1[fa[x][i]].size()-1;
		for(int j=pos;j<=n;j+=lb(j)) tr1[fa[x][i]][j]+=v;
		pos=dis[x][i-1];
		for(int j=pos;j<=n && j;j+=lb(j)) tr2[fa[x][i]][j]+=v;
	}
}
int main(){
	int n=read(),m=read();
	for(int i=1;i<=n;i++) val[i]=read();
	for(int x,y,i=1;i<n;i++){
		x=read(),y=read();
		add(x,y);add(y,x);
	}
	dp[0]=INF;sum=n;getroot(1,0);buildtree(rt);
	for(int i=1;i<=n;i++) fa[i][d[i]+1]=i;
	for(int i=1;i<=n;i++) change(i,val[i]);
	int ans=0;
	while(m--){
		int op=read(),x=read()^ans,k=read()^ans;
		if(!op) ans=query(x,k),cout<<ans<<"\n";
		else change(x,k-val[x]),val[x]=k;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章