【HDU 3887 Counting Offspring】 dfs序+树状数组

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3887

 

题目大意: 给你一颗n个节点的数,对于每个节点i,问你每个节点的子树中有多少个节点序列数小于i,求f[i]。

解题思路:

   用样例来说明,我们可以先深搜一遍,那么深搜得到的序列就是  7,3,15,15,12, 12, 3, 4, 4, 1, 1, 10, 14, 13, 13, 2, 2, 14, 10,……9, 7

   对这个序列进行分析可以发现,举例:3,15,15,12, 12, 3 , 节点3中间的数就是它的子树序列。

  dfs打好序列后就对序列进行遍历一遍,开两个st[], sd[] 数组, 存每个节点开始和结束位置。接下来就是树状数组求和,注意这里要序列从大到小求和(也就是n-->1),求完后删掉对应位置的数,树状数组进行相应的更新操作。

 

 1 #pragma comment(linker, "/STACK:1024000000,1024000000")
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cstring>
 7 using namespace std;
 8 
 9 const int maxn=100005;
10 vector<int>vt[maxn];
11 int bit[2*maxn];
12 int que[2*maxn];
13 int st[maxn];
14 int sd[maxn];
15 int f[maxn];
16 int n, rt, num;
17 
18 void dfs(int u, int fa)
19 {
20     que[++num]=u;
21     for(int i=0; i<vt[u].size(); i++)
22     {
23         int v=vt[u][i];
24         if(v==fa) continue;
25         dfs(v,u);
26     }
27     que[++num]=u;
28 }
29 
30 int lowbit(int x)
31 {
32     return x&(-x);
33 }
34 
35 void cal(int x, int val)
36 {
37     while(x<=num)
38     {
39         bit[x]+=val;
40         x+=lowbit(x);
41     }
42 }
43 
44 int getsum(int x)
45 {
46     int ans=0;
47     while(x>0)
48     {
49         ans+=bit[x];
50         x-=lowbit(x);
51     }
52     return ans;
53 }
54 
55 int main()
56 {
57     while(~scanf("%d%d",&n,&rt),n+rt)
58     {
59         for(int i=0; i<=n; i++)
60             vt[i].clear();
61         for(int i=1; i<n; i++)
62         {
63             int x, y;
64             scanf("%d%d",&x,&y);
65             vt[x].push_back(y);
66             vt[y].push_back(x);
67         }
68         fill(st+1,st+1+n,0);
69         num=0;
70         dfs(rt,-1);
71         for(int i=1; i<=num; i++)
72         {
73             if(!st[que[i]]) st[que[i]]=i;
74             else sd[que[i]]=i;
75         }
76         memset(bit,0,sizeof(bit));
77         for(int i=1; i<=num; i++)
78             cal(i,1);
79         for(int i=n; i>=1; i--)
80         {
81             f[i]=(getsum(sd[i]-1)-getsum(st[i]))/2;
82             cal(st[i],-1);
83             cal(sd[i],-1);
84         }
85         printf("%d",f[1]);
86         for(int i=2; i<=n; i++)
87             printf(" %d",f[i]);
88         puts("");
89     }
90     return 0;
91 }

 

转载于:https://www.cnblogs.com/kane0526/archive/2013/01/10/2855125.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值