hdu 3887 Counting Offspring(DFS序【非递归】+树状数组)

题意:

N个点形成一棵树。给出根结点P还有树结构的信息。

输出每个点的F[i]。F[i]:以i为根的所有子结点中编号比i小的数的个数。

0<n<=10^5

思路:

方法一:直接DFS,进入结点x时记录一下比x小的数的个数。出来x时记录一下比x小的数的个数。相减就是F[x]。结合树状数组。

方法二:写下DFS序。对DFS序列建线段树。然后从小到大对结点进行插入。用线段树统计。

代码:(方法一)

int const N=1e5+5;

int n,p;
vector<int> G[N];
int C[N];
int ans[N];
stack<int> S;
bool vis[N];



void Add(int x){
    for(int i=x;i<=n;i+=lowbit(i)){
        C[i]++;
    }
}
int query(int x){
    int ret=0;
    for(int i=x;i>0;i-=lowbit(i)){
        ret+=C[i];
    }
    return ret;
}

void dfs(int u){
    while(!S.empty()){
        S.pop();
    }
    mem(vis,false);
    S.push(u);
    vis[u]=true;
    while(!S.empty()){
        int now=S.top();
        int L=G[now].size();
        bool flag=false;
        rep(i,0,L-1){
            if(vis[G[now][i]]==false){
                vis[G[now][i]]=true;
                flag=true;
                int t=G[now][i];
                ans[t]=query(t-1);
                S.push(G[now][i]);
                break;
            }
        }
        if(!flag){
            ans[now]=query(now-1)-ans[now];
            Add(now);
            S.pop();
        }
    }
}

int main(){

    while(scanf("%d%d",&n,&p)!=EOF,n||p){

        rep(i,1,n) G[i].clear();
        mem(C,0);
        mem(ans,0);

        rep(i,1,n-1){
            int a,b;
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        dfs(p);
        rep(i,1,n-1) printf("%d ",ans[i]); cout<<ans[n]<<endl;
    }

    return 0;
}
原文地址:https://www.cnblogs.com/fish7/p/4317921.html