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
",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
",getsum(e[t])-getsum(b[t]-1));
        }
    }
    return 0;
}


 

原文地址:https://www.cnblogs.com/james1207/p/3281255.html