poj 3321

题目链接

题意:一开始1-n都有苹果,Q查询以x为根下存在多少。

树状数组+DFS+队列转换

这题纠结了2天,一开始一点思路都没有,看大神都是吧树状数组转换成队列来做

看了好久都不知道怎么转换的,

解决方法:用两个队列,一个是以记录(s,u),s为起点,一个记录s,为终点

用DFS查找一棵分支,记录访问次序,这样就可以转换成树状数组了

 

#include <cstdio> //参照大神的代码

#include <cstring>

using namespace std;

#define N 500000

int tree[N],b[N],e[N],head[N];  //b记录DFS访问的次序,e表示当前节点DFS的最后一个节点标号

bool h[N],v[N]; //v[i]表示是否被访问过

int num;

struct node

{

    int x,next;

}a[N];

inline int lowbit(int x) {return x&-x;}

void update(int x,int t)

{

    int n;

    if(h[t]) {h[t]=false;n=-1;} //false 表示没有

    else {h[t]=true;n=1;}

    while(x<=num)

    {

        tree[x]+=n;

        x+=lowbit(x);

    }

}

int getsum(int x)

{

    int ans=0;

    while(x>0)

    {

        ans+=tree[x];

        x-=lowbit(x);

    }

    return ans;

}

void dfs(int x)

{

    v[x]=true;

    b[x]=++num;

    for(int i=head[x];i!=-1;i=a[i].next)

    {

        if(!v[a[i].x])

            dfs(a[i].x);

    }

    e[x]=num;

  //printf("%d  %d %d\n",x,num,b[x]);

}

int main()

{

    int n,i,j;

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

    {

        int m=0;

        memset(tree,0,sizeof(tree));

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

        for(i=1;i<n;i++)

        {

            int s,u;

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

            m++;

            a[m].x=u;a[m].next=head[s];head[s]=m;

            m++;

            a[m].x=s;a[m].next=head[u];head[u]=m;

        }

        memset(v,false,sizeof(v));

        memset(b,0,sizeof(b));

        memset(e,0,sizeof(e));

        num=0;

        dfs(1);

        for(i=1;i<=n;i++)

        {

            update(b[i],i);

            h[i]=true;

        }

        char str[10];

        int t,mm;

        scanf("%d",&mm);

        for(i=1;i<=mm;i++)

        {

            scanf("%s%d",str,&t);

            if(str[0]=='C')

            update(b[t],t);

            else

            printf("%d\n",getsum(e[t])-getsum(b[t]-1));

        }

    }

    return 0;

}


 

 

你可能感兴趣的:(poj)