题目,是对一颗树,单点修改、子树查询。典型的dfs序入门题。
DFS序可以将一颗树与子树们表示为一个连续的区间,然后用线段树来维护;感觉算是树链剖分的一种吧,和轻重链剖分不同的是这是对子树进行剖分的。
我用非递归方式求DFS序。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 111111 6 struct Edge{ 7 int v,nxt; 8 }edge[MAXN<<1]; 9 int n,NE,head[MAXN]; 10 void addEdge(int u,int v){ 11 edge[NE].v=v; edge[NE].nxt=head[u]; head[u]=NE++; 12 } 13 14 int f[MAXN],l[MAXN],r[MAXN],stack[MAXN],odr; 15 void dfs(){ 16 int top=0; 17 stack[++top]=1; 18 while(top){ 19 int u=stack[top]; 20 if(l[u]){ 21 r[u]=++odr; --top; 22 continue; 23 } 24 l[u]=++odr; 25 for(int i=head[u]; i!=-1; i=edge[i].nxt){ 26 int v=edge[i].v; 27 if(f[u]==v) continue; 28 f[v]=u; stack[++top]=v; 29 } 30 } 31 } 32 33 int N,tree[MAXN<<3],x,y; 34 void update(int i,int j,int k){ 35 if(i==j){ 36 tree[k]^=1; 37 return; 38 } 39 int mid=i+j>>1; 40 if(x<=mid) update(i,mid,k<<1); 41 else update(mid+1,j,k<<1|1); 42 tree[k]=tree[k<<1]+tree[k<<1|1]; 43 } 44 int query(int i,int j,int k){ 45 if(x<=i&&j<=y) return tree[k]; 46 int mid=i+j>>1,res=0; 47 if(x<=mid) res=query(i,mid,k<<1); 48 if(y>mid) res+=query(mid+1,j,k<<1|1); 49 return res; 50 } 51 52 int main(){ 53 int m,a,b; 54 char op[11]; 55 memset(head,-1,sizeof(head)); 56 scanf("%d",&n); 57 for(int i=1; i<n; ++i){ 58 scanf("%d%d",&a,&b); 59 addEdge(a,b); 60 addEdge(b,a); 61 } 62 dfs(); 63 for(N=1; N<odr; N<<=1); 64 for(int i=1; i<=n; ++i){ 65 x=l[i]; 66 update(1,N,1); 67 } 68 scanf("%d",&m); 69 while(m--){ 70 scanf("%s%d",op,&a); 71 if(op[0]==‘Q‘){ 72 x=l[a]; y=r[a]; 73 printf("%d\n",query(1,N,1)); 74 }else{ 75 x=l[a]; 76 update(1,N,1); 77 } 78 } 79 return 0; 80 }
时间: 2024-12-27 23:33:58