【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 }