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 }

猜你喜欢

转载自www.cnblogs.com/Lin88/p/9973575.html