并不是太难,只要处理换根操作就好了,因为这棵树的形态是不变的。那么按照点1为根时的dfs序,若当前根在x点的子树外,则答案还是x的子树,若当前根是x,那么答案是整棵树,若当前的根在x的子树内,则答案就是抠掉根所在的那一枝后的答案(画个图就明白了)。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #define maxn 100010 #define inf 1000000000 using namespace std; struct yts { int data; int l,r; }a[4*maxn]; int e[maxn],next[2*maxn],head[maxn],to[2*maxn],g[maxn],w[maxn],in[maxn],out[maxn]; int fa[maxn][20],dep[maxn]; int n,m,root,num,T,tot; void addedge(int x,int y) { num++;to[num]=y;next[num]=head[x];head[x]=num; } void dfs(int x) { e[++tot]=x;in[x]=tot; for (int p=head[x];p;p=next[p]) if (to[p]!=g[x]) dep[to[p]]=dep[x]+1,dfs(to[p]); out[x]=tot; } void build(int i,int l,int r) { a[i].l=l;a[i].r=r; if (l==r) {a[i].data=w[e[l]];return;} int mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); a[i].data=min(a[i*2].data,a[i*2+1].data); } void modify(int i,int x,int d) { if (a[i].l==a[i].r) {a[i].data=d;return;} int mid=(a[i].l+a[i].r)/2; if (x<=mid) modify(i*2,x,d); if (mid<x) modify(i*2+1,x,d); a[i].data=min(a[i*2].data,a[i*2+1].data); } int query(int i,int l,int r) { if (l>r) return inf; if (l<=a[i].l && a[i].r<=r) return a[i].data; int mid=(a[i].l+a[i].r)/2,ans=inf; if (l<=mid) ans=min(ans,query(i*2,l,r)); if (mid<r) ans=min(ans,query(i*2+1,l,r)); return ans; } int go_up(int x,int d) { for (int i=19;i>=0;i--) if (d&(1<<i)) x=fa[x][i]; return x; } int main() { scanf("%d%d",&n,&T); for (int i=1;i<=4*n;i++) a[i].data=inf; for (int i=1;i<=n;i++) scanf("%d%d",&g[i],&w[i]); for (int i=1;i<=n;i++) if (g[i]) addedge(g[i],i); else root=i; dep[1]=0;dfs(1); for (int i=1;i<=n;i++) fa[i][0]=g[i]; for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1]; else fa[i][j]=0; build(1,1,n); while (T--) { char op[5]; int x,y; scanf("%s%d",op,&x); if (op[0]=='V') { scanf("%d",&y); modify(1,in[x],y); } if (op[0]=='E') root=x; if (op[0]=='Q') { if (root==x) printf("%d\n",query(1,1,n)); else if (in[x]<=in[root] && out[root]<=out[x]) { int y=go_up(root,dep[root]-dep[x]-1); printf("%d\n",min(query(1,1,in[y]-1),query(1,out[y]+1,n))); } else printf("%d\n",query(1,in[x],out[x])); } } return 0; }