1. 程式人生 > 其它 >洛谷 P3178 [HAOI2015]樹上操作(樹剖+線段樹)

洛谷 P3178 [HAOI2015]樹上操作(樹剖+線段樹)

傳送門


解題思路

好板子啊。
要不是是個省選題
我才不寫部落格呢。

樹剖完了,就是單點修改+區間修改+區間求和。
線段樹維護即可。

AC程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100005;
long long d[maxn*4],lazy[maxn*4];
int n,m,p[maxn],cnt,siz[maxn],fa[maxn],son[maxn],id[maxn],tp[maxn],a[maxn],dfn[maxn],times;
struct node{
	int v,next;
}e[maxn*2];
void insert(int u,int v){
	cnt++;
	e[cnt].v=v;
	e[cnt].next=p[u];
	p[u]=cnt;
}
void dfs1(int u,int f){
	siz[u]=1;
	fa[u]=f;
	for(int i=p[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==f) continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int top){
	dfn[u]=++times;
	id[times]=u;
	tp[u]=top;
	if(son[u]) dfs2(son[u],top);
	for(int i=p[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==son[u]||v==fa[u]) continue;
		dfs2(v,v);
	}
}
void pushdown(int id,int l,int r){
	if(lazy[id]){
		int mid=(l+r)/2;
		lazy[id*2]+=lazy[id];
		lazy[id*2+1]+=lazy[id];
		d[id*2]+=1ll*(mid-l+1)*lazy[id];
		d[id*2+1]+=1ll*(r-mid)*lazy[id];
		lazy[id]=0;
	}
}
void pushup(int id){
	d[id]=d[id*2]+d[id*2+1];
}
void update(int id,int l,int r,int x,int y,long long v){
	if(x>y) return;
	if(x<=l&&r<=y){
		d[id]+=v*(r-l+1);
		lazy[id]+=v;
		return;
	}
	int mid=(l+r)/2;
	pushdown(id,l,r);
	if(x<=mid) update(id*2,l,mid,x,y,v);
	if(y>mid) update(id*2+1,mid+1,r,x,y,v);
	pushup(id);
}
long long query(int id,int l,int r,int x,int y){
	if(x>y) return 0;
	if(x<=l&&r<=y){
		return d[id];
	}
	pushdown(id,l,r);
	int mid=(l+r)/2;
	long long res=0;
	if(x<=mid) res+=query(id*2,l,mid,x,y);
	if(y>mid) res+=query(id*2+1,mid+1,r,x,y);
	return res;
}
int main(){
	ios::sync_with_stdio(false);
	memset(p,-1,sizeof(p));
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		insert(u,v);
		insert(v,u);
	}
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=n;i++) update(1,1,n,dfn[i],dfn[i],a[i]);
	for(int i=1;i<=m;i++){
		int op;
		cin>>op;
		if(op==1){
			int u,x;
			cin>>u>>x;
			update(1,1,n,dfn[u],dfn[u],x);
			continue;
		}
		if(op==2){
			int u,x;
			cin>>u>>x;
			update(1,1,n,dfn[u],dfn[u]+siz[u]-1,x);
			continue;
		}
		if(op==3){
			int x;
			long long ans=0;
			cin>>x;
			while(x!=0){
				ans+=query(1,1,n,dfn[tp[x]],dfn[x]);
				x=fa[tp[x]];
			}
			cout<<ans<<endl;
		}
	}
	return 0;
}