HDOJ3887-DFS人工栈,树状数组

来源:互联网 发布:软件企业认定 招标 编辑:程序博客网 时间:2024/04/30 02:27
/* 树状数组。dfs过程中,进入一个节点x前求一次sum(x-1),然后add操作,递归返回节点x后再求一次sum(x-1)       两次sum操作的差值就是比x小的个数       本题数据量大,递归太深可能爆栈,一般用while+人工栈模拟递归的过程,当然c++可以设置栈的大小,这样就不会爆栈了我不告诉你思路是看来的~~可取的是人工栈过了一遍。*/  #include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;const int NN=100010;vector<int> v[NN];int n,r;int s[NN],c[NN],cur[NN],pre[NN];bool vis[NN];int lowbit(int x){    return x&(-x);}void update(int x,int w){    while (x<=n)    {        c[x]+=w;        x+=lowbit(x);    }}int getsum(int x){    int ret=0;    while (x)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}int ss[NN],top;void dfs(){    ss[top=1]=r;    pre[r]=0;    vis[r]=true;    update(r,1);    while (top)    {        int x=ss[top];        for (int &i=cur[x]; i<v[x].size(); i++)        {            int y=v[x][i];            if (!vis[y])            {                vis[y]=true;                pre[y]=getsum(y-1);                update(y,1);                ss[++top]=y;                break;            }        }        if (cur[x]==v[x].size())        {            s[x]=getsum(x-1)-pre[x];            top--;        }    }}int main(){    while (scanf("%d%d",&n,&r)!=EOF && n|r)    {        for (int i=1; i<=n; i++)        {            v[i].clear();            c[i]=0;            s[i]=0;            vis[i]=false;            cur[i]=0;        }        int x,y;        for (int i=1; i<n; i++)        {            scanf("%d%d",&x,&y);            v[x].push_back(y);            v[y].push_back(x);        }        dfs();        printf("%d",s[1]);        for (int i=2; i<=n; i++) printf(" %d",s[i]);        printf("\n");    }    return 0;}