poj 3321 树状数组,灵活
同上一题一样,记录dfs遍历的序列,然后再利用树状数组快速求和
调了好久呢
View Code
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
stack<int> ss;
const int maxn = 100010;
struct EDGE{
int v,next;
}edge[maxn*2];
int exis[maxn],head[maxn],l[maxn],r[maxn],seq[maxn*2],re[maxn],c[maxn*2],cnt;
bool vis[maxn];
int tot;
void add(int a,int b){
edge[tot].v=a; edge[tot].next=head[b];head[b]=tot;re[b]=tot++;
edge[tot].v=b; edge[tot].next=head[a];head[a]=tot;re[a]=tot++;
}
int lowbit(int x){
return x&-x;
}
void update(int x,int d){
for(;x<2*maxn;x+=lowbit(x))
c[x]+=d;
}
int sum(int x){
int ans=0;
for(;x>0;ans+=c[x],x-=lowbit(x));
return ans;
}
void dfs(int root){
cnt=1;
while(!ss.empty()) ss.pop();
memset(vis,false,sizeof(vis));
ss.push(root);
while(!ss.empty())
{
int now=ss.top();
if(!vis[now])
{
seq[cnt]=now;
l[now]=cnt++;
vis[now]=true;
}
bool flag=false;
for(int i=re[now];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].v])
{
flag=true;
ss.push(edge[i].v);
re[now]=edge[i].next;//记录当前点遍历到了第几个邻接点了,返回的时候从这个邻接点开始
break;
}
}
if(flag) continue;
if(vis[now])
{
seq[cnt]=now;
r[now]=cnt++;
ss.pop();
}
}
/* for(int i=1;i<cnt;i++)
{
printf("%d ",seq[i]);//1 3 3 2 2 1
}
puts("");*/
}
int main(){
int n,root,i,j,a,b,m;
char op[5];
while(scanf("%d",&n)!=EOF){
tot=0;
memset(head,-1,sizeof(head));
memset(re,-1,sizeof(re));
memset(c,0,sizeof(c));
for(i=1;i<n;i++){
scanf("%d%d",&a,&b);
add(a,b);
}
dfs(1);
for(i=1;i<=n;i++)
{
exis[i]=1;//开始的时候全部的节点上都有苹果
update(l[i],1);
}
scanf("%d",&m);
while(m--)
{
int x;
scanf("%s%d",op,&x);
if(op[0]=='Q')
{
if(l[x]==1) printf("%d\n",sum(r[x]));
else
printf("%d\n",sum(r[x])-sum(l[x]-1));
}
else
{
if(exis[x])
{
update(l[x],-1);
exis[x]=0;
}
else
{
update(l[x],1);
exis[x]=1;
}
}
}
}
return 0;
}