[BZOJ]1103: [POI2007]大都市meg
题目大意:一棵n个点的树,边权均为1,两种操作,一种把一条边边权改为0,另一种查询一个点到根的路径长度。(n<=250,000)
思路:预处理出一开始各个点的答案,每次修改操作把子树内的所有答案减1,求出dfs序后用线段树维护即可,复杂度O(nlogn)。
#include<cstdio> #include<algorithm> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 250000 #define N 262144 struct edge{int nx,t;}e[MN*2+5]; int h[MN+5],en,l[MN+5],r[MN+5],cnt,d[MN+5],t[N*2+5]; inline void ins(int x,int y) { e[++en]=(edge){h[x],y};h[x]=en; e[++en]=(edge){h[y],x};h[y]=en; } void dfs(int x,int fa) { l[x]=++cnt; for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)d[e[i].t]=d[x]+1,dfs(e[i].t,x); r[x]=cnt; } void dec(int l,int r) { for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1) { if(~l&1)--t[l+1]; if( r&1)--t[r-1]; } } int query(int x){int r=d[x];for(x=l[x]+N;x;x>>=1)r+=t[x];return r;} int main() { int n=read(),i,x;char s[5]; for(i=1;i<n;++i)ins(read(),read()); dfs(1,0); for(i=read()+n-1;i--;) { scanf("%s",s); if(s[0]=='W')printf("%d\n",query(read())); else x=max(read(),read()),dec(l[x],r[x]); } }