修改某条路径上的值以及询问子树的最小值都是最树剖的基础操作,那么如何实现换根呢?
考虑一下三种情况:
1.rot=询问的子树x,答案就是整棵树的最小值
2.rot在x的子树里,只有rot到x这一条链上的的节点的子树会变
找到x在rot方向上的子节点,答案就是除去这棵子树的最小值
3.rot不在x的子树里,那么rot是谁对x的子树没有影响,答案不变
那么就在询问时分类讨论一下就好了
#include<complex> #include<cstdio> using namespace std; const int INF=1<<30; const int N=1e5+7; struct node{ int v,nxt; }e[N<<1]; int n,m,s,Enum,tim,rot; int val[N],front[N],fa[N][20]; int fat[N],dep[N],tid[N],son[N],siz[N],top[N],rank[N]; int tree[N<<2],lazy[N<<2]; inline int qread() { int x=0,j=1; char ch=getchar(); while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)j=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*j; } inline void Insert(int u,int v) { e[++Enum].v=v; e[Enum].nxt=front[u]; front[u]=Enum; } void dfs1(int x) { siz[x]=1; fa[x][0]=fat[x]; for(int i=front[x];i;i=e[i].nxt) { int v=e[i].v; if(v==fat[x])continue; fat[v]=x; dep[v]=dep[x]+1; dfs1(v); siz[x]+=siz[v]; if(siz[v]>siz[son[x]]) son[x]=v; } } void dfs2(int x,int tp) { top[x]=tp; tid[x]=++tim; rank[tid[x]]=x; if(!son[x])return; dfs2(son[x],tp); for(int i=front[x];i;i=e[i].nxt) { int v=e[i].v; if(v!=son[x] && v!=fat[x]) dfs2(v,v); } } inline void PushUp(int rt) { tree[rt]=min(tree[rt<<1],tree[rt<<1|1]); } inline void PushDown(int rt) { if(lazy[rt]) { tree[rt<<1]=tree[rt<<1|1]=lazy[rt]; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; lazy[rt]=0; } } void Build(int l,int r,int rt) { if(l==r) { tree[rt]=val[rank[l]]; return; } int mid=l+r>>1; Build(l,mid,rt<<1); Build(mid+1,r,rt<<1|1); PushUp(rt); } void Modify(int l,int r,int rt,int nowl,int nowr,int v) { if(nowl<=l && r<=nowr) { tree[rt]=lazy[rt]=v; return; } PushDown(rt); int mid=l+r>>1; if(nowl<=mid)Modify(l,mid,rt<<1,nowl,nowr,v); if(mid<nowr)Modify(mid+1,r,rt<<1|1,nowl,nowr,v); PushUp(rt); } int Query(int l,int r,int rt,int nowl,int nowr) { if(nowl<=l && r<=nowr) return tree[rt]; PushDown(rt); int mid=l+r>>1,a=INF,b=INF; if(nowl<=mid)a=Query(l,mid,rt<<1,nowl,nowr); if(mid<nowr)b=Query(mid+1,r,rt<<1|1,nowl,nowr); return min(a,b); } void FindFather() { for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } inline int Lca(int a,int b) { if(dep[a]<dep[b])swap(a,b); int tmp=dep[a]-dep[b]; for(int i=19;i>=0;i--) if(tmp&(1<<i)) a=fa[a][i]; if(a==b)return a; for(int i=19;i>=0;i--) if(fa[a][i]!=fa[b][i]) { a=fa[a][i]; b=fa[b][i]; } return fa[a][0]; } inline void ModifyRoad(int x,int y,int v) { int f1=top[x],f2=top[y]; while(f1!=f2) { if(dep[f1]<dep[f2])swap(f1,f2),swap(x,y); Modify(1,n,1,tid[f1],tid[x],v); x=fat[f1];f1=top[x]; } if(dep[x]>dep[y])swap(x,y); Modify(1,n,1,tid[x],tid[y],v); } inline int QueryTree(int x) { if(x==rot)return tree[1]; int lca=Lca(x,rot); if(lca==x) { int tmp=dep[rot]-dep[x]-1,v=rot; for(int i=0;i<=19;i++) if(tmp&(1<<i)) v=fa[v][i]; return min(Query(1,n,1,1,tid[v]-1),Query(1,n,1,tid[v]+siz[v],n)); } return Query(1,n,1,tid[x],tid[x]+siz[x]-1); } int main() { scanf("%d%d",&n,&m); int u,v,p,x; for(int i=1;i<=n-1;i++) { u=qread();v=qread(); Insert(u,v); Insert(v,u); } for(int i=1;i<=n;i++) val[i]=qread(); dfs1(1);dfs2(1,1); Build(1,n,1); FindFather(); scanf("%d",&rot); for(int i=1;i<=m;i++) { p=qread(); if(p==1)rot=qread(); if(p==2) { u=qread();v=qread();x=qread(); ModifyRoad(u,v,x); } if(p==3) { x=qread(); printf("%d\n",QueryTree(x)); } } return 0; }