1. 程式人生 > >Codeforces 1076E Vasya and a Tree(樹狀陣列)

Codeforces 1076E Vasya and a Tree(樹狀陣列)

題意:給你一顆以1為根節點的樹,初始所有節點的權值為0,然後有m個操作,每個操作將點x的所有距離不超過d的節點權值+1,問經過m次操作後每個節點權值是多少?

思路:如果是一個序列,就可以直接用樹狀陣列做,但這是一顆樹,所以我們可以想辦法把它轉化成序列。我們可以先求出每個節點的dfs序,以及深度和子樹的大小,順便記錄每個深度都有哪些節點,子樹的大小用來確認以該節點為根的子樹在dfs序中的範圍,此時便可用樹狀陣列維護了。之後,我們把每個操作按能影響到的深度從大到小排序,即優先處理影響深度大的操作。設當前計算的深度為now,假設所有操的作影響的深度大於now的操作已經計算。如果當前操作影響的深度小於now,說明所有能影響到now深度的操作已經全部操作完了,此時把所有深度為now的節點權值計算出來。每讀取一個操作的資訊,就把操作產生的影響用樹狀陣列維護,因為影響now深度的節點權值已經計算完畢了,所以我把以該操作的操作節點為根的子樹全部加上操作的值 對之前已經計算的答案沒有影響。操作全部完成後,深度從深到淺計算答案即可。

程式碼:

#include<bits/stdc++.h>
#define LL long long
#define lowbit(x) (x&(-(x)))
using namespace std;
const int maxn=300010;
int deep[maxn],head[maxn],Next[maxn*2],ver[maxn*2],tot,cnt;
int sum[maxn],sz[maxn],dfsn[maxn],mx,n;
LL c[maxn],ans[maxn];
struct op{
	int x,d;
	LL num;
	bool operator <(const op& rhs)const{
		return (deep[x]+d)>(deep[rhs.x]+rhs.d);
	} 
}OP[maxn];
void adde(int x,int y){
	ver[++tot]=y;
	Next[tot]=head[x];
	head[x]=tot;
}
vector<int>re[maxn];
int get_deep(int x,int dep){
	deep[x]=dep;
	dfsn[x]=++cnt;
	sz[x]=1;
	mx=max(mx,dep);
	re[dep].push_back(x);
	for(int i=head[x];i;i=Next[i]){
		int y=ver[i];
		if(!deep[y]){
			get_deep(y,dep+1);
			sz[x]+=sz[y];
		}
	}
}
LL ask(int x){
	LL ans=0;
	for(;x;x-=lowbit(x))ans+=c[x];
	return ans;
}
void add(int x,LL y){
	for(;x<=n;x+=lowbit(x))c[x]+=y;
}
int main(){
	int m;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		adde(a,b);
		adde(b,a);
	}
	get_deep(1,1);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int a,b;
		LL c;
		scanf("%d%d%lld",&a,&b,&c);
		OP[i]=(op){a,b,c};
	}
	sort(OP+1,OP+1+m);
	int now=mx;
	for(int i=1;i<=m;i++){
		int tmp=deep[OP[i].x]+OP[i].d;
		while(now>tmp){
			for(int j=0;j<re[now].size();j++){
				int x=re[now][j];
				ans[x]=ask(dfsn[x]);
			}
			now--;
		}
		add(dfsn[OP[i].x],OP[i].num);
		add(dfsn[OP[i].x]+sz[OP[i].x],-OP[i].num);
	}
	while(now){
		while(now){
			for(int j=0;j<re[now].size();j++){
				int x=re[now][j];
				ans[x]=ask(dfsn[x]);
			}
			now--;
		}
	}
	for(int i=1;i<=n;i++)
		printf("%lld ",ans[i]);
}