HDU 3887 Counting Offspring 树状数组

时间:2022-10-30 04:54:12
/*
题意:1-n在一棵树上,给定边的关系。要求得到每一个顶点的后继节点中比它值小的个数
题解:树状数组。dfs过程中,进入一个节点x前求一次sum(x-1),然后add操作,递归返回节点x后再求一次sum(x-1)
      两次sum操作的差值就是比x小的个数
本题数据量大,递归太深可能爆栈,一般用while+人工栈模拟递归的过程,当然c++可以设置栈的大小,这样就不会爆栈了	  
*/
#include <cstdio>
#include <iostream>
#include <memory.h>
#include<queue>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN=100009; 
const int N=100009;
int n,root;

struct Edge
{
    int v,next;
}edge[2*MAXN+10];
int first[MAXN],e,f[MAXN],p[MAXN],pre[MAXN];
inline void addedge(int u,int v)
{
    edge[e].v=v;edge[e].next=first[u],first[u]=e++;
    edge[e].v=u;edge[e].next=first[v],first[v]=e++;
}
void init()
{
    memset(first,-1,sizeof(first));
    memset(f,0,sizeof(f));
    e=0;
    int u,v;
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d",&u,&v);
        addedge(u,v);
    }
}
int ar[N];  
inline int lowb(int t){return t&(-t);}  
  
void add(int i,int v)  
{  
    for(;i<N;ar[i]+=v,i+=lowb(i));  
}  
int sum(int i)  
{  
    int s=0;  
    for(;i>0;s+=ar[i],i-=lowb(i));  
    return s;    
}  
void dfs(int x,int fa)
{
    pre[x]=sum(x-1);
    for(int k=first[x];k!=-1;k=edge[k].next)
    {
        if(edge[k].v!=fa)
        {
            p[edge[k].v]=x;
            add(edge[k].v,1);
            dfs(edge[k].v,x);
        }        
    }
    f[x]=sum(x-1)-pre[x];
}

void solve()
{
    memset(ar,0,sizeof(ar));
    dfs(root,root);
    for(int i=1;i<n;i++)
    printf("%d ",f[i]);
    printf("%d\n",f[n]);
    
}
int main () 
{
    while(scanf("%d%d",&n,&root),n+root)
    {
        init();
        solve();
    }
    return 0;    
}