HDU 3887 Counting Offspring (树状数组+人工模拟栈)

对这棵树DFS遍历一遍,同一节点入栈和出栈之间访问的节点就是这个节点的子树。

因此节点入栈时求一次 小于 i 的节点个数 和,出栈时求一次 小于 i 的节点个数 和,两次之差就是答案。

PS.这题直接DFS会爆栈,可以重新设置栈的大小

#pragma comment(linker,"/STACK:100000000,100000000")

也可以人工模拟栈,代码如下。

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>



using namespace std;



const int MAXN = 110000;



struct Edge

{

    int v;

    int next;

};



int N, root;

int EdgeN, top;

Edge D[ (MAXN << 2) + 100 ];

int C[ MAXN ];     //树状数组

int ans[ MAXN ];   //答案

int pre[ MAXN ];   //入点前的和

int head[ MAXN ];

int stack[MAXN];   //手工栈

bool vis[MAXN];



int lowbit( int x )

{

    return x&(-x);

}



int query( int x )

{

    int res = 0;

    while ( x > 0 )

    {

        res += C[x];

        x -= lowbit(x);

    }

    return res;

}



void update( int x, int val )

{

    while ( x <= N )

    {

        C[x] += val;

        x += lowbit(x);

    }

    return;

}



void AddEdge( int u, int v )

{

    D[EdgeN].v = v;

    D[EdgeN].next = head[u];

    head[u] = EdgeN++;

    return;

}



void showStack( int top )

{

    for ( int i = 1; i <= top; ++i )

        printf( "%d ", stack[i] );

    puts("\n===================");

    return;

}



void DFS( int u )

{

    stack[++top] = u;

    vis[u] = true;

    while ( top )

    {

        int uu = stack[top];

        if ( !vis[uu] ) pre[uu] = query(uu - 1);

        vis[uu] = true;

        int i;

        for ( i = head[uu]; i != -1; i = D[i].next )

        {

            if ( !vis[ D[i].v ] )

            {

                update( D[i].v, 1 );

                stack[++top] = D[i].v;

                //showStack(top);

                break;

            }

        }

        if ( i == -1 )

        {

            ans[uu] = query( uu - 1 ) - pre[uu];

            --top;

        }

    }

    return;

}



int main()

{

    //freopen( "s.txt", "w", stdout );

    while ( scanf( "%d%d", &N, &root ), N || root )

    {

        EdgeN = 1;

        memset( head, -1, sizeof(head) );

        memset( C, 0, sizeof(C) );



        for ( int i = 1; i < N; ++i )

        {

            int u, v;

            scanf( "%d%d", &u, &v );

            AddEdge( u, v );

            AddEdge( v, u );

        }



        top = 0;

        memset( vis, false, sizeof(vis) );

        memset( pre, 0, sizeof(pre) );

        DFS( root );



        printf( "%d", ans[1] );

        for ( int i = 2; i <= N; ++i )

            printf( " %d", ans[i] );

        puts("");

    }

    return 0;

}

 

你可能感兴趣的:(spring)