• 【POJ 3321】Apple Tree


    有n个节点以1为根节点的树,给你树的边关系u-v,一开始每个节点都有一个苹果,接下来有两种操作,C x改变节点x的苹果状态,Q x查询x为根的树的所有苹果个数。

     
    求出树的dfs序,st[i]保存i的进入时间戳,ed[i]保存i的退出时间戳,则st[i]到ed[i]就是子树节点的对应时间戳。
    每个节点打了两次时间戳,其中ed[i]会等于最后访问的一个子节点的st[i]。
    于是用线段树/树状数组的单点修改和区间求和就可以解决。
    #include<cstdio>
    #define N 100005
    using namespace std;
    int n,m,id,cnt;
    int q[N],st[N],ed[N],head[N];
    int rl[N<<2],rr[N<<2],sum[N<<2];
    struct edge{
        int to,next;
    }e[N<<1];
    void add(int u,int v){
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
    }
    void dfs(int x,int fa){
        st[x]=++id;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa)
                dfs(e[i].to,x);
        ed[x]=id;
    }
    void build(int k,int l,int r){
        rl[k]=l;rr[k]=r;
        if(l==r){
            sum[k]=1;
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    int query(int k,int a,int b){
        int l=rl[k],r=rr[k];
        if(a<=l&&r<=b) return sum[k];
        if(b<l||a>r)return 0;
        return query(k<<1,a,b)+query(k<<1|1,a,b);
    }
    void modify(int k,int x){
        int l=rl[k],r=rr[k],mid=(l+r)>>1;
        if(l==r){
            sum[k]^=1;
            return;
        }
        if(x<=mid)modify(k<<1,x);
        else modify(k<<1|1,x);
        sum[k]=sum[k<<1]+sum[k<<1|1];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1,0);
        scanf("%d",&m);
        build(1,1,n);
        for(int i=1;i<=m;i++){
            char op;
            scanf(" %c",&op);
            int x;
            scanf("%d",&x);
            if(op=='Q')
                printf("%d
    ",query(1,st[x],ed[x]));
            else
                modify(1,st[x]);
        }
        return 0;
    }

    树状数组

    #include<cstdio>
    #define N 100005
    using namespace std;
    int n,m,id,cnt;
    int q[N],st[N],ed[N],head[N];
    int cal[N],a[N];
    struct edge{
        int to,next;
    }e[N<<1];
    void add(int u,int v){
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
    }
    void dfs(int x,int fa){
        st[x]=++id;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa)
                dfs(e[i].to,x);
        ed[x]=id;
    }
    int getsum(int x){
        int s=0;
        for(;x;x-=x&(-x))s+=cal[x];
        return s;
    }
    void update(int v,int x){
        for(;x<=n;x+=x&(-x))cal[x]+=v;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        dfs(1,0);
        scanf("%d",&m);
        for(int i=1;i<=n;i++)update(1,i);
        for(int i=1;i<=m;i++){
            char op;
            scanf(" %c",&op);
            int x;
            scanf("%d",&x);
            if(op=='C'){
                update(a[x]?1:-1,st[x]);
                a[x]^=1;
            }
            else
                printf("%d
    ",getsum(ed[x])-getsum(st[x]-1));
        }
        return 0;
    }

      

  • 相关阅读:
    Apache Commons 工具集使用简介
    程序员最核心的竞争力是什么?
    开发FTP不要使用sun.net.ftp.ftpClient
    Eclipse和MyEclipse工程描述符.classpath和.project和.mymetadata详解(转)
    MAC OS X显示.开头的文件_苹果操作系统显示隐藏文件命令
    再探二分查找
    二叉树的各种操作
    【java】求两个字符串的最长公共子串
    【Java】数组不能通过toString方法转为字符串
    【C语言】数组名传递给函数,数组的sizeof变为4的原因
  • 原文地址:https://www.cnblogs.com/flipped/p/5705948.html
Copyright © 2020-2023  润新知