1. 程式人生 > >Educational Codeforces Round #54 (Div. 2) E. Vasya and a Tree 技巧題

Educational Codeforces Round #54 (Div. 2) E. Vasya and a Tree 技巧題

題目連線:http://codeforces.com/contest/1076/problem/E

  本題大意:

  給一棵根節點為“1”樹,給m個操作,每個操作三個整數,v,d,x,意思是從節點1,往下深度d,遍及的節點的值都加上x,d可能是0,就是隻加在自己上。結束m個操作後輸出每個節點的值。

 

  解題思路:

  這裡不應該考慮同時操作整棵樹。因為每個節點的子樹是多樣的,而應該以dfs的形式,直接搜到葉子節點,這樣沿途就是一條鏈。每時每刻都在操作一條鏈,也就是一段區間。這樣操作轉化為:一個節點往後的距離為d的區間內都加上x,這樣問題就轉變成了區間修改的問題,利用樹狀陣列來實現。

  存在疑問的地方應該是,當搜不同的葉子節點的時候,鏈是不一樣的,如何鏈的變化。只要想一下,從一個葉子到另一個葉子,不就是區間修改——把前一個葉子的影響去掉,然後加上另一個葉子的影響不就好了嗎?也就是說,dfs回退是把回退掉的點的影響去掉,這在樹狀陣列上實現就是回退時加上一個-x就好了。

下面是AC程式碼:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=3e5+7;
 5 struct Node
 6 {
 7     int v,next;
 8 }a[N<<1];
 9 struct Flag//記錄操作
10 {
11     int d,x;
12 };
13 int n,cnt;
14 
15 int head[N];//前向星
16 inline void add(int u,int v)
17 {
18     a[cnt].v=v;
19 a[cnt].next=head[u]; 20 head[u]=cnt++; 21 } 22 23 ll tr[N],ans[N];//樹狀陣列,答案 24 inline void update(int x,int v) 25 { 26 for(;x<N;x+=x&-x) 27 tr[x]+=v; 28 } 29 30 inline ll sum(int x) 31 { 32 ll ret=0; 33 for(;x>0;x-=x&-x) 34 ret+=tr[x]; 35 return ret;
36 } 37 38 vector<Flag> v[N];//儲存每個節點的操作 39 bool vis[N]; 40 void dfs(int now,int dep) 41 { 42 vis[now]=1; 43 int nd,nx; 44 45 for(int i=0;i<v[now].size();++i)//讓當前節點的操作生效 46 { 47 nd=min(dep+v[now][i].d,n); 48 nx=v[now][i].x; 49 update(dep,nx); 50 update(nd+1,-nx); 51 } 52 53 ans[now]=sum(dep);//記錄當前節點的值 54 55 for(int i=head[now];i!=-1;i=a[i].next)//繼續往下 56 { 57 if(vis[a[i].v]) 58 continue; 59 dfs(a[i].v,dep+1); 60 } 61 62 for(int i=0;i<v[now].size();++i)//回退時把在該節點生效的操作撤銷 63 { 64 nd=min(dep+v[now][i].d,n); 65 nx=v[now][i].x; 66 update(dep,-nx);//樹狀陣列上加上負數 67 update(nd+1,nx); 68 } 69 } 70 int main() 71 { 72 int x,y; 73 memset(head,-1,sizeof(head)); 74 scanf("%d",&n); 75 for(int i=1;i<n;++i) 76 { 77 scanf("%d%d",&x,&y); 78 add(x,y); 79 add(y,x); 80 } 81 int q; 82 scanf("%d",&q); 83 int t; 84 Flag temp; 85 for(int i=1;i<=q;++i) 86 { 87 scanf("%d%d%d",&t,&temp.d,&temp.x);//把操作裝到各點的vector裡 88 v[t].push_back(temp); 89 } 90 dfs(1,1); 91 for(int i=1;i<n;++i) 92 printf("%lld ",ans[i]); 93 printf("%lld\n",ans[n]); 94 }