华华和月月种树(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 }

 

posted @ 2020-08-22 13:27  一个只会爆零的小菜鸡  阅读(127)  评论(0编辑  收藏  举报