看了下noi的水题 然后第一次自己YY出dfs序这个东西(当然以前听别人讲过没写过)
然后做了一道dfs序的水题
做法:
统计出一个点的dfs序,成为pos[i]和以该节点为子树的所有点中pos[i]的最大值en[i]
然后用树状数组单点修改区间询问处理
可以把询问的过程想象为一次dfs,走到一条边ans++,返回ans--,那么对于一个点我们add(pos[x],1) add(en[x]+1,-1)来模拟这个过程 也就是去掉分叉的影响,不妨加一个超级源连在1号点,那么每次都是通过一条边来到了这里,所以query(pos[i])就是通过的边数,然而超级源的边不能计算,所以ans--。
对于修改,一条边会使他的子树里的所有点的答案都-1,所以add(pos[x],-1) add(en[x]+1,1)
然而bzoj上不用手写栈
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; const int Maxn=250000+10; int pos[Maxn],en[Maxn],clk=0; struct Edge{ int to; Edge*next; Edge(int to=0,Edge*next=0):to(to),next(next) {} }pool[Maxn*2],*fir[Maxn],*pis=pool; void AddEdge(int from,int to) { *pis=Edge(to,fir[from]);fir[from]=pis++; *pis=Edge(from,fir[to]);fir[to]=pis++; } int fa[Maxn]; void dfs(int x) { pos[x]=++clk; for(Edge*p=fir[x];p;p=p->next) { int v=p->to; if(v==fa[x]) continue; fa[v]=x; dfs(v); } en[x]=clk; } int C[Maxn],n; void add(int x,int d) { for(;0<x&&x<=n;x+=x&-x) C[x]+=d; } int query(int x) { int ret=0; for(;0<x&&x<=n;x-=x&-x) ret+=C[x]; return ret; } int main() { #ifdef DEBUG freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); AddEdge(u,v); } dfs(1); for(int i=1;i<=n;i++) { add(pos[i],1); add(en[i]+1,-1); } int m; for(scanf("%d",&m);m;) { char opt; int x,y; while(opt=getchar(),opt!='A'&&opt!='W'); if(opt=='A') { scanf("%d%d",&x,&y); if(fa[y]==x) swap(x,y); add(pos[x],-1); add(en[x]+1,1); }else { scanf("%d",&x); printf("%d ",query(pos[x])-1); m--; } } return 0; }