CF Div2 E. Vasya and a Tree(思維 + 線段樹)
阿新 • • 發佈:2018-11-25
題目連結:
題意:
給定一個以 1 為根節點的樹,初始每個節點的權值為 0 。有 m 次操作,每次把以 vi 為祖先且離 vi 的距離小於 di 的所有節點(包括 vi 本身)的權值加上 xi 。問所有操作結束後,每個節點的權值。
思路:
一個點只會影響它的子孫節點(包括自己),且只會被它的祖先節點影響(包括自己)。
所以,我們 dfs 到一個節點 v 時,我們把以它為操作物件的操作完成,那麼相當於對於該節點的所有操作都已被完成,那麼我們可以直接算出這個節點的最終權值。當 dfs 回溯到該節點時,我們把之前做的操作刪除即可,因為關於該節點的操作不能影響不以該節點為祖先的節點。這樣一次 dfs 就能算出所有節點的最終答案。
那麼,操作怎樣進行呢?我們知道:到當前為止的所有操作都會對該節點的子孫產生影響(如果在範圍內的話),所以比如說操作為v,d,x,當前節點深度為dep,那麼所有深度在 [dep,dep+d] 範圍內的節點都要加 x 。因此我們可以用線段樹來維護區間和。當前節點的最終權值就是用線段樹查詢區間 [dep,dep] 的權值和。
Code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAX = 3e5+10; const ll mod = 1e9+7; typedef struct{ int d; ll x; }Point; int n,m; vector<int>mp[MAX]; vector<Point>op[MAX]; ll sum[MAX<<2],Add[MAX<<2]; ll res[MAX]; /*線段樹*/ void Pushup(int root) { sum[root]=sum[root<<1]+sum[root<<1|1]; } void Build(int l,int r,int root) { if(l==r){ sum[root]=0; return; } int mid = (l+r)>>1; Build(l,mid,root<<1); Build(mid+1,r,root<<1|1); Pushup(root); } void Pushdown(int root,int ln,int rn) { if(Add[root]){ Add[root<<1]+=Add[root]; Add[root<<1|1]+=Add[root]; sum[root<<1]+=Add[root]*ln; sum[root<<1|1]+=Add[root]*rn; Add[root]=0; } } void Update(int L,int R,ll c,int l,int r,int root) { if(L<=l&&r<=R){ sum[root]+=c*(r-l+1); Add[root]+=c; return; } int mid = (l+r)>>1; Pushdown(root,mid-l+1,r-mid); if(L<=mid) Update(L,R,c,l,mid,root<<1); if(R>mid) Update(L,R,c,mid+1,r,root<<1|1); Pushup(root); } ll Query(int L,int R,int l,int r,int root) { if(L<=l&&r<=R){ return sum[root]; } int mid = (l+r)>>1; Pushdown(root,mid-l+1,r-mid); ll ans=0; if(L<=mid) ans+=Query(L,R,l,mid,root<<1); if(R>mid) ans+=Query(L,R,mid+1,r,root<<1|1); return ans; } /*線段樹*/ void dfs(int root,int fa,int dep) { //新增操作 for(int i=0;i<op[root].size();i++){ Point now = op[root][i]; Update(dep,min(dep+now.d,n),now.x,1,n,1); } res[root]=Query(dep,dep,1,n,1); for(int i=0;i<mp[root].size();i++){ int v = mp[root][i]; if(v==fa) continue; dfs(v,root,dep+1); } //刪除操作 for(int i=0;i<op[root].size();i++){ Point now = op[root][i]; Update(dep,min(dep+now.d,n),-1*now.x,1,n,1); } } int main() { scanf("%d",&n); for(int i=0;i<n-1;i++){ int x,y; scanf("%d%d",&x,&y); mp[x].push_back(y); mp[y].push_back(x); } Build(1,n,1); scanf("%d",&m); while(m--){ int v,d; ll x; scanf("%d%d%lld",&v,&d,&x); op[v].push_back(Point{d,x}); } dfs(1,-1,1); printf("%lld",res[1]); for(int i=2;i<=n;i++){ printf(" %lld",res[i]); } printf("\n"); return 0; }