题解:
维护x到1的土路条数;
修改一条边相当于修改一个区间;
用树状数组差分实现
对某一个点的贡献相当于求前缀和;
实际上我维护的是公路条数,本质一样
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=300000; const int inf=1000000000; int n,m; int cntedge; int head[maxn]; int nex[maxn<<1],to[maxn<<1]; int addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int idx[maxn],father[maxn],siz[maxn]; int depth[maxn]; int temp; int dfs(int now,int fa){ depth[now]=depth[fa]+1; father[now]=fa; idx[now]=(++temp); siz[now]=1; for(int i=head[now];i;i=nex[i]){ if(to[i]==fa)continue; dfs(to[i],now); siz[now]+=siz[to[i]]; } } int f[maxn][21]; int Lcainit(){ for(int i=1;i<=n;++i)f[i][0]=father[i]; for(int j=1;j<=20;++j){ for(int i=1;i<=n;++i){ f[i][j]=f[f[i][j-1]][j-1]; } } } int Getlca(int u,int v){ if(depth[u]<depth[v])swap(u,v); for(int j=20;j>=0;--j){ if(depth[f[u][j]]>=depth[v])u=f[u][j]; } if(u==v)return u; for(int j=20;j>=0;--j){ if(f[u][j]!=f[v][j]){ u=f[u][j]; v=f[v][j]; } } return father[u]; } int c[maxn]; inline int lowbit(int x){ return x&(-x); } int add(int x,int val){ while(x<=n){ c[x]+=val; x+=lowbit(x); } } int query(int x){ int ret=0; while(x){ ret+=c[x]; x-=lowbit(x); } return ret; } int main(){ scanf("%d",&n); for(int i=1;i<=n-1;++i){ int x,y; scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs(1,0); scanf("%d",&m); m=n+m-1; while(m--){ char opty=getchar(); while((opty!=‘W‘)&&(opty!=‘A‘))opty=getchar(); int x,y; if(opty==‘A‘){ scanf("%d%d",&x,&y); if(depth[x]>depth[y])swap(x,y); add(idx[y],1); add(idx[y]+siz[y],-1); }else{ scanf("%d",&x); printf("%d\n",depth[x]-1-query(idx[x])); } } return 0; }