poj 3321 dfs序 树状数组 前向星

 

题意概括

有一颗01树,以结点1为树根,一开始所有的结点权值都是1,有两种操作:

  1.改变其中一个结点的权值(0变1,1变0)

  2.询问子树X的节点权值和。

参考博客 http://www.cnblogs.com/zhouzhendong/p/7265431.html

思路 :dfs序  +树状数组

题目变成dfs序上   单点修改  和区间sum询问的问题。

单点修改,不用线段树,树状数组就可以了

用vector存图超时。。改用的前向星

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;

const int N = 1E5+3;
const int M = 2E5+3;
#define pb push_back
int n;
int in[N],out[N];
int time;
int vis[N];
int tree[N],a[N];
struct edge{
    int cnt,y[M],nxt[M],head[N];
    void clc(){
        cnt =0 ;
        memset(head,0,sizeof(head));
    }
    void add(int a,int b){
        y[++cnt]=b;
        nxt[cnt]=head[a];head[a]=cnt;
    }
}E;


void dfs(int t){
    in[t]=++time;
    vis[t]=1;
    for(int i =E.head[t];i;i=E.nxt[i]){
        if(vis[E.y[i]])continue;
        vis[E.y[i]]=1;
        dfs(E.y[i]);
    }
    out[t]=time;
}
int lowbit(int x){
    return x&-x;
}
int sum(int x){
    int ans=0;
    for(;x>0;x-= x&-x){
        ans+=tree[x];
    }
    return ans;
}
void update(int x,int val){
    for(;x<=n;x+= x&-x)
        tree[x]+=val;
}


int main(){

    int u,v;
    char s[22];int x;
    while(cin>>n){

        time=0;
        memset(vis,0,sizeof(vis));
        E.clc();
        for(int i=1;i<n;++i){
            scanf("%d %d",&u,&v);
            E.add(u,v);
        }
        for(int i=1;i<=n;++i)a[i]=1,tree[i]=lowbit(i);

        dfs(1);

        int q;
        cin>> q;
        while(q--){
            scanf("%s %d",s,&x);
            if(s[0]=='Q'){
                printf("%d\n",sum(out[x])-sum(in[x]-1) );
            }
            else if(s[0]=='C'){
                update(in[x] ,1-a[x]*2),a[x]=a[x]^1;
            }
        }
    }
    return 0;
}

 

 

posted on 2018-10-21 22:00  Helpp  阅读(143)  评论(0编辑  收藏  举报

导航