BZOJ 4034 树上操作

熟练剖分

不想写树剖怎么办QwQ
维护每个点(Ans)
操作(1)就是子树加
操作(2)是操作(1)的叠加......
认真分析......
子树加(dep)!!!

写个树状数组节省一下码量
(节省了还是100+)
(我选择死亡)

#include <cstdio>

const int MAXN=100111;

int N, M;
int X;
long long op;
long long Ans;

struct Vert{
	int FE;
	int Dps, Dpr;
	int Dep;
	long long Val, Sum;
} V[MAXN];

struct Edge{
	int x, y, next;
} E[MAXN<<1];

int Ecnt;

void addE(int a, int b){
	++Ecnt;
	E[Ecnt].x=a;E[Ecnt].y=b;E[Ecnt].next=V[a].FE;V[a].FE=Ecnt;
}

int Dfn[MAXN], DFN;

void DFS(int at, int f=0){
	++DFN;
	Dfn[DFN]=at;
	V[at].Dps=DFN;
	for(int k=V[at].FE, to;k>0;k=E[k].next){
		to=E[k].y;
		if(to==f)	continue;
		V[to].Dep=V[at].Dep+1;
		V[to].Sum=V[at].Sum+V[to].Val;
		DFS(to, at);
	}
	V[at].Dpr=DFN;
}

int lowbit(int a){
	return a&(-a);
}

struct Trray{
	int L;
	long long n[MAXN];
	void init(int l){
		L=l;
		for(int i=0;i<MAXN;++i)	n[i]=0LL;
	}
	long long Ask(int p){
		long long ret=0LL;
		for(int i=p;i>0;i-=lowbit(i))
			ret+=n[i];
		return ret;
	}
	void Update(int l, int r, long long d){
		for(int i=l;i<=L;i+=lowbit(i))		n[i]+=d;
		for(int i=r+1;i<=L;i+=lowbit(i))	n[i]-=d;
	}
} Cv, Cd;

int main(){
	
	scanf("%d%d", &N, &M);
	
	for(int i=1;i<=N;++i)	scanf("%lld", &V[i].Val);
	
	for(int i=1, a, b;i<N;++i){
		scanf("%d%d", &a, &b);
		addE(a, b);addE(b, a);
	}
	
	V[1].Dep=1;
	V[1].Sum=V[1].Val;
	DFS(1);
	
	Cv.init(DFN);Cd.init(DFN);
	
	for(int t;M--;){
		scanf("%d", &t);
		if(t==1){
			scanf("%d%lld", &X, &op);
			Cv.Update(V[X].Dps, V[X].Dpr, op);
		}
		if(t==2){
			scanf("%d%lld", &X, &op);
			Cd.Update(V[X].Dps, V[X].Dpr, op);
			Cv.Update(V[X].Dps, V[X].Dpr, -op*(long long)(V[X].Dep-1));
		}
		if(t==3){
			scanf("%d", &X);
			Ans=V[X].Sum;
			Ans+=Cv.Ask(V[X].Dps);
			Ans+=Cd.Ask(V[X].Dps)*(long long)(V[X].Dep);
			printf("%lld
", Ans);
		}
	}
	
	return 0;
}

/*
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

6
9
13

*/

原文地址:https://www.cnblogs.com/Pickupwin/p/9545222.html