1. 程式人生 > 實用技巧 >華華和月月種樹(dfs序+樹狀陣列)

華華和月月種樹(dfs序+樹狀陣列)

連結:https://ac.nowcoder.com/acm/problem/23051
來源:牛客網

題意

對一棵樹(初始只有 0 號節點,權值為 0)進行操作和詢問:

操作 1:輸入格式1i,表示使節點 i 長出了一個新的兒子節點,權值為0,編號為當前最大編號 +1(也可以理解為,當前是第幾個操作 1,新節點的編號就是多少)。
操作 2:輸入格式 2ia,表示華華上線做任務使節點 i 的子樹中所有節點(即它和它的所有子孫節點)權值加 a 。

詢問 3:輸入格式3i,華華需要給出 i 節點此時的權值。

思路

先將樹變成dfs序,然後就是樹狀陣列了。當在節點 i 進行操作 2 的時候,就相當 [ dfn[i] , dfn[i]+sz[i]-1 ]範圍加上a。當進行操作 1 的時候,只需要把新加入的節點權值變成0即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e5+10;
 5 vector<int>v[maxn];
 6 int n,m,cnt;
 7 int dfn[maxn];//dfs序,相當於節點在樹狀陣列中的下標
 8 int sz[maxn]; //sz[i] 表示節點 i 為根的子樹的所有節點數z
 9 int tree[maxn];
10 struct query
11 {
12     int op,i,a;
13 }q[maxn<<2];
14 
15
int sum(int x) 16 { 17 int s=0; 18 while (x>0) 19 { 20 s+=tree[x]; 21 x-=(x&-x); 22 } 23 return s; 24 } 25 26 void update(int x,int s) 27 { 28 while(x<=cnt) 29 { 30 tree[x]+=s; 31 x+=(x&-x); 32 } 33 } 34 35 void dfs(int u)
36 { 37 sz[u]++; 38 dfn[u]=++cnt; 39 for(int i:v[u]) 40 { 41 dfs(i); 42 sz[u]+=sz[i]; 43 } 44 } 45 46 void solve() { 47 scanf("%d",&m); 48 for(int i=0;i<m;i++) 49 { 50 scanf("%d%d",&q[i].op,&q[i].i); 51 if(q[i].op==1) 52 { 53 v[q[i].i].push_back(++n); 54 q[i].i=n; //記錄新加入的子節點 55 } 56 else if(q[i].op==2) 57 scanf("%d",&q[i].a); 58 } 59 dfs(0); 60 for(int i=0;i<m;i++) 61 { 62 if(q[i].op==1) 63 { 64 int v=sum(dfn[q[i].i]); 65 update(dfn[q[i].i],-v); 66 update(dfn[q[i].i]+1,v); 67 } 68 else if(q[i].op==2) 69 { 70 update(dfn[q[i].i],q[i].a); 71 update(dfn[q[i].i]+sz[q[i].i],-q[i].a); 72 } 73 else 74 printf("%d\n",sum(dfn[q[i].i])); 75 } 76 } 77 78 signed main() { 79 solve(); 80 return 0; 81 }