华华和月月种树(dfs序+树状数组)
链接:https://ac.nowcoder.com/acm/problem/23051
来源:牛客网
题意
对一棵树(初始只有 0 号节点,权值为 0)进行操作和询问:
操作 1:输入格式1 i,表示使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。
操作 2:输入格式 2 i a,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。
询问 3:输入格式3 i,华华需要给出 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 }