Bzoj 4034.樹上操作(歐拉序+線段樹)

題意: 有一棵點數爲 N 的樹,以點 1 爲根,且樹點有邊權。然後有 M 個

操作,分爲三種:

操作 1 :把某個節點 x 的點權增加 a 。

操作 2 :把某個節點 x 爲根的子樹中所有點的點權都增加 a 。

操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。

題解: 直接維護樹的歐拉序,將第一次進入的標記爲+1,回溯時出去的標記爲-1,如此前綴和便是x到根的點權和,每個節點都會在歐拉序中出現兩次,第一個操作便是單點修改,第二次操作便是將第一次出現到第二次出現的區間修改,線段樹維護即可

#include<bits/stdc++.h>
using namespace std;
#define Sheryang main
const int maxn=2e5+7;
typedef long long ll;
const int mod=1e9+7;
///#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
///char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
#define IO cin.tie(0),ios::sync_with_stdio(false);
#define pi acos(-1)
#define PII pair<ll,ll>
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
/** keep hungry and keep calm! **/

int Time,w[maxn],pos[maxn],n,f[maxn],dfn[maxn],_dfn[maxn],oula[maxn];
vector<int>G[maxn];
void dfs(int u,int fa){
	oula[++Time] = u; 
	dfn[u] = Time;
	f[Time] = 1;
	int sz = G[u].size();
	for(int i = 0 ; i<sz ; i++){
		int v = G[u][i];
		if(v==fa) continue;
		dfs(v,u);
	}
	oula[++Time] = u;
	_dfn[u] = Time;
	f[Time] = -1;
}

ll sum[maxn<<4],lazy[maxn<<4],Lazy[maxn<<4],sumf[maxn<<4];
void pushup(int rt){
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
	sumf[rt] = sumf[rt<<1] + sumf[rt<<1|1];
}

void build(int l=1,int r=2*n,int rt=1){
	if(l==r){
		sum[rt] = w[oula[l]]*f[l];
		sumf[rt] = f[l];
		return;
	}
	int mid = l+r>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	pushup(rt);
}

void pushdown(int rt){
	if(lazy[rt]){
		lazy[rt<<1] += lazy[rt];
		lazy[rt<<1|1] += lazy[rt];
		
		sum[rt<<1] += lazy[rt]*sumf[rt<<1];
		sum[rt<<1|1] += lazy[rt]*sumf[rt<<1|1];
		
		lazy[rt] = 0;
	}
}

void update(int l,int r,int vol,int L=1,int R=2*n,int rt=1){
	if(L>=l && R<=r){
		sum[rt] += 1LL*vol*sumf[rt];
		lazy[rt] += vol;
		pushdown(rt);
		return;
	}
	pushdown(rt);
	int mid = L+R>>1;
	if(l<=mid){
		update(l,r,vol,L,mid,rt<<1);
	}
	if(r>mid){
		update(l,r,vol,mid+1,R,rt<<1|1);
	}
	pushup(rt);
}

ll query(int l,int r,int L=1,int R=2*n,int rt=1){
	if(L>=l && R<=r){
		return sum[rt];
	}
	pushdown(rt);
	int mid = L+R>>1;
	ll ans = 0;
	if(l<=mid){
		ans += query(l,r,L,mid,rt<<1);
	}
	if(r>mid){
		ans += query(l,r,mid+1,R,rt<<1|1);
	}
	return ans;
}

int Sheryang(){
    
    n=read;
	int m=read;
    
    for(int i=1;i<=n;i++){
    	w[i] = read;
	}
	
	for(int i=1;i<n;i++){
		int u=read,v=read;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	
	dfs(1,0);
	build();

	for(int i=0;i<m;i++){
		int op=read;
		if(op==1){
			int x=read,vol=read;
			update(dfn[x],dfn[x],vol);
			update(_dfn[x],_dfn[x],vol);
		}else if(op==2){
			int x=read,vol=read;
			update(dfn[x],_dfn[x],vol);
		}else{
			int x=read;
			printf("%lld\n",query(1,dfn[x]));
		}
	}
    return 0;
}

//    1
//  2   4
// 3 5 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章