【hdu 4918】Query on the subtree 动态树分治

先填上,以后来说
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#define maxm 4000021
#define maxn 100021
using namespace std;
int n,m,head[maxn],tot=1,cnt,val[maxn],dep[maxn],dfn[maxn];
int f[maxn],s[maxn],size,rt,vis[maxn],last[maxn],tt=1;
struct edge{int v,next;}e[maxn*2];
void adde(int a,int b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}
struct node{
	int rt,id,dis,next;
	node(int a=0,int b=0,int c=0,int d=0):rt(a),id(b),dis(c),next(d){}
}nod[maxm];
void ade(int a,int rt,int id,int dis){
	nod[tt]=node(rt,id,dis,last[a]);
	last[a]=tt++;
}
struct T{
	int n;
	vector<int>c;
	void init(int x){
		n=x;c.clear();
		for(int i=0;i<=n;i++)c.push_back(0);
	}
	void add(int x,int y){
		if(!x)return ;
		while(x<=n){c[x]+=y;x+=x&-x;}
	}
	int query(int x){
		if(x>n)x=n;
		int ans=0;
		while(x>0){ans+=c[x];x-=x&-x;}
		return ans;
	}
}T[maxn*2];
void pre(){
	tot=tt=1,cnt=0;
	for(int i=1;i<=n;i++)head[i]=vis[i]=last[i]=0;
}
void getrt(int u,int fa){
	s[u]=1,f[u]=0;
	for(int v,i=head[u];i;i=e[i].next){
		if(vis[v=e[i].v]||v==fa)continue;
		getrt(v,u);
		s[u]+=s[v];
		if(s[v]>f[u])f[u]=s[v];
	}
	f[u]=max(f[u],size-s[u]);
	if(f[u]<f[rt])rt=u;
}
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;
	ade(u,rt,cnt,dep[u]);
	T[cnt].add(dep[u],val[u]);
	T[dfn[rt]].add(dep[u],val[u]); 
	for(int v,i=head[u];i;i=e[i].next){
		if(vis[v=e[i].v]||v==fa)continue;
		dfs(v,u);
	}
}
void solve(int u){
	vis[u]=1,dfn[u]=++cnt;
	T[cnt].init(size+1); 
	T[cnt].add(1,val[u]);
	ade(u,u,0,1);dep[u]=1;
	for(int v,i=head[u];i;i=e[i].next){
		if(vis[v=e[i].v])continue;
		cnt++;T[cnt].init(s[v]+1);//!!!!!!!!!! 
		dfs(v,u);
	}
	for(int v,i=head[u];i;i=e[i].next){
		if(vis[v=e[i].v])continue;
		f[rt=0]=size=s[v];
		getrt(v,u);
		solve(rt);
	}
}
void work(){
	char s[5];int a,b;
	while(m--){
		scanf("%s%d%d",s,&a,&b);
	//printf("<%d>\n",T[3].query(1) );
		if(s[0]=='?'){
			int ans=0;
			for(int r,id,d,i=last[a];i;i=nod[i].next){
				r=nod[i].rt,id=nod[i].id,d=nod[i].dis;
				ans+=T[dfn[r]].query(b-d+2);
				if(id)ans-=T[id].query(b-d+2);
			}
			printf("%d\n",ans);
		}else{
			for(int r,id,d,i=last[a];i;i=nod[i].next){
				r=nod[i].rt,id=nod[i].id,d=nod[i].dis;
				T[dfn[r]].add(d,b-val[a]);
				if(id)T[id].add(d,b-val[a]); 
				
			}
			val[a]=b;
		}
	}
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		pre();
		for(int i=1;i<=n;i++)scanf("%d",val+i);
		for(int a,b,i=1;i<n;i++){
			scanf("%d%d",&a,&b);
			adde(a,b),adde(b,a);
		}
		f[rt=0]=size=n;
		getrt(1,0);
		solve(rt);
		work();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值