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; }