换根其实很简单,我们考虑换根对答案的影响,换根不会对链上信息有任何影响,所以我们只考虑子树方面
1.当前的根root不在询问点u的子树中,表示虽然换了根,但u在以root为根的树中的子树就和在以最初的根的树中的子树一样
2.当前的根在询问点u的子树中,那么u在以root为根的树中的子树就是u到root路径上第一个点在以最初的根的树中的子树之外的部分
这两个部分画图好理解
特判一下u=root 的情况,此时对全局做出操作
例题:
一棵有根树,三个操作
1.换根
2.单点修改
3.查询子树最小值
Code:
#include<bits/stdc++.h>
#define INF 1e9
#define ls tr[k].l
#define rs tr[k].r
#define mid ((ls+rs)>>1)
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=100005;
int a[N],id[N],root=1,ff[N];
namespace segtree{
struct seg{int l,r,minn;}tr[N<<2];
inline void pushup(int k){tr[k].minn=min(tr[k<<1].minn,tr[k<<1|1].minn);}
inline void build(int k,int l,int r){
ls=l,rs=r;
if(l==r) {tr[k].minn=a[id[l]];return;}
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify(int k,int pos,int val){
if(ls==rs) {tr[k].minn=val;return;}
if(pos<=mid) modify(k<<1,pos,val);
else modify(k<<1|1,pos,val);
pushup(k);
}
inline int query(int k,int ql,int qr){
if(qr<ql) return INF;
if(qr<ls || ql>rs) return INF;
if(ql<=ls && rs<=qr) return tr[k].minn;
if(qr<=mid) return query(k<<1,ql,qr);
else if(ql>mid) return query(k<<1|1,ql,qr);
else return min(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr));
}
};
using namespace segtree;
int n,m;
int vis[N<<1],nxt[N<<1],head[N<<1],tot=0;
int pt[N],siz[N],dep[N],fa[N],hson[N];
int dfn[N],top[N],sign=0;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs1(int v){
pt[v]=siz[v]=1;int maxn=0;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(pt[y]) continue;
fa[y]=v;dep[y]=dep[v]+1;
dfs1(y);
siz[v]+=siz[y];
if(siz[y]>maxn) maxn=siz[y],hson[v]=y;
}
}
void dfs2(int v){
dfn[v]=++sign;id[sign]=v;
if(hson[v]) {top[hson[v]]=top[v];dfs2(hson[v]);}
for(int i=head[v];i;i=nxt[i]) if(!top[vis[i]]) top[vis[i]]=vis[i],dfs2(vis[i]);
}
inline int lca(int x,int y){
while(top[x]!=top[y])
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
return dep[x]<dep[y]?x:y;
}
inline int find(int f,int s){
for(int i=head[f];i;i=nxt[i]){
if(vis[i]==ff[f]) continue;
if(dfn[vis[i]]<=dfn[root] && dfn[vis[i]]+siz[vis[i]]-1>=root) return vis[i];
}
return 0;
}
inline int ask(int u){
if(u==root) return query(1,1,n);
else if(lca(u,root)!=u) return query(1,dfn[u],dfn[u]+siz[u]-1);
int v=find(u,root);
return min(query(1,1,dfn[v]-1),query(1,dfn[v]+siz[v],n));
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
ff[i]=read();a[i]=read();
if(i!=1) add(ff[i],i),add(i,ff[i]);
}
dfs1(1);top[1]=1;dfs2(1);build(1,1,n);
while(m--){
char op;
scanf("%c",&op);
if(op=='E') root=read();
else if(op=='V') {int p=read(),v=read();modify(1,dfn[p],v);}
else cout<<ask(read())<<'\n';
}
return 0;
}