题目大意:
有一颗树 每个节点最多生长一个苹果,有两种操作
1.改变某个节点状态(有苹果去掉,没有苹果加上一个)
2.求某个节点的子树上苹果的个数
直接做肯定会超时 ,如果整棵树是一条链的话,时间复杂度就会很高。
解决方法:
运用时间戳,dfs遍历一遍树,每个节点分别记录他自己的编号,和他的子节点中编号最大的编号,这样就把求节点子树的问题转化为了求线性区间和问题了。
然后运用线段树,就能够顺利解决了。
我的代码
#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
#define maxn 1000005
using namespace std;
int head[maxn];
struct ED{
int x;
int next;
}edge[maxn];
int totll;
int L[maxn],R[maxn];
int vis[maxn],totl;
int tree[maxn*3];
int dfs(int v,int fa){
vis[v]=++totl;
L[v]=totl;
for(int i=head[v];i;i=edge[i].next){
if (edge[i].x!=fa){
dfs(edge[i].x,v);
}
}
R[v]=totl;
return 0;
}
int build (int o,int L,int R){
if (L==R) tree[o]=1;
else {
int M=L+(R-L)/2;
build (o*2,L,M);
build (o*2+1,M+1,R);
tree[o]=tree[o*2+1]+tree[o*2];
}
return 0;
}
int yy;
int change(int o,int L,int R){
if (L==R&&L==yy) {
if (tree[o]) tree[o]=0;
else tree[o]=1;
}
else {
int M=L+(R-L)/2;
if (yy<=M) change(o*2,L,M);
if (yy>M) change (o*2+1,M+1,R);
tree[o]=tree[o*2]+tree[o*2+1];
}
return 0;
}
int y1,y2,_sum;
int query(int o,int L,int R){
if (y1<=L&&y2>=R) _sum+=tree[o];
else {
int M=L+(R-L)/2;
if (y1<=M) query(o*2,L,M);
if (y2>M) query(o*2+1,M+1,R);
}
return 0;
}
int main (){
int n,m;
while (scanf("%d",&n)!=EOF){
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
totll=0;
for (int i=0;i<n-1;i++){
int a,b;
scanf("%d%d",&a,&b);
int bbb=head[a];
head[a]=++totll;
edge[totll].x=b;
edge[totll].next=bbb;
bbb=head[b];
head[b]=++totll;
edge[totll].x=a;
edge[totll].next=bbb;
}
totl=0;dfs(1,0);
build(1,1,n);
scanf("%d",&m);
for (int i=0;i<m;i++){
char c[2];scanf("%s",c);
int x;scanf("%d",&x);
if (c[0]=='Q'){
_sum=0;
y1=L[x];y2=R[x];
query(1,1,n);
cout<<_sum<<endl;
}
if (c[0]=='C'){
yy=vis[x];
change(1,1,n);
}
}
}
return 0;
}
注意:不要使用vector类 否则会超时,最好使用邻接表。