传送门:bzoj3083
这篇题解,必须要写(这道简单题真的坑到我了)…好久没打树剖的下场。
除开换根都是裸树剖+线段树。
以1号节点为根建树。换根可以 O(1) O ( 1 ) 换,只需要在查询的时候讨论一下:
若当前查询的节点 id i d 不在1到 root r o o t 的路径上,直接查询子树信息( dfs d f s 序上的 in,out i n , o u t )。
反之,当前以 id i d 为根的子树便是整棵树去掉以 x x 向 root r o o t 方向的第一个子节点 为根的子树,跳重链到这个子节点 x′ x ′ 即可, id i d 子树 dfs d f s 区间便为 [1,in[x′]−1]∪[out[x′]+1,n] [ 1 , i n [ x ′ ] − 1 ] ∪ [ o u t [ x ′ ] + 1 , n ] 。
这里需要特殊判断一种情况:当 id==root i d == r o o t 时,子树为 [1,n] [ 1 , n ] (不然会WA得很惨TAT)。
注意几点(主要是必须熟练打板):
总之做这道题的体验十分不好TAT,以后要多做DS,锻炼码力QAQ
#include
#define gc getchar()
#define si isdigit(c)
#define lc k<<1
#define rc k<<1|1
#define mid (((l)+(r))>>1)
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll inf=1LL<<33;
int n,m,in[N],ot[N],d[N],rv[N],dfn;
int head[N],to[N<<1],nxt[N<<1],tot;
int rt,son[N],sz[N],top[N],f[N];
ll a[N],mn[N<<2],st[N<<2],ans;
char c;
template<class T>
inline void rd(T &x)
{
c=gc;x=0;
for(;!si;c=gc);
for(;si;c=gc) x=x*10+(c^48);
}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
inline void dfs(int x)
{
int i,j;
sz[x]=1;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x]) continue;
f[j]=x;d[j]=d[x]+1;dfs(j);sz[x]+=sz[j];
if(sz[j]>sz[son[x]]) son[x]=j;
}
}
inline void dfss(int x,int tp)
{
top[x]=tp;in[x]=++dfn;rv[dfn]=x;
if(son[x]) dfss(son[x],tp);
int i,j;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x] || j==son[x]) continue;
dfss(j,j);
}
ot[x]=dfn;
}
inline void pushup(int k)
{mn[k]=min(mn[lc],mn[rc]);}
inline void pushdown(int k)
{
if(!st[k]) return;
st[lc]=st[rc]=st[k];
mn[lc]=mn[rc]=st[k];
st[k]=0;
}
inline void build(int k,int l,int r)
{
if(l==r){mn[k]=a[rv[l]];return;}
build(lc,l,mid);build(rc,mid+1,r);
pushup(k);
}
inline void sett(int k,int l,int r,int L,int R,ll vv)
{
if(L<=l && r<=R) {st[k]=mn[k]=vv;return;}
pushdown(k);
if(L<=mid) sett(lc,l,mid,L,R,vv);
if(R>mid) sett(rc,mid+1,r,L,R,vv);
pushup(k);
}
inline ll ask(int k,int l,int r,int L,int R)
{
if(L>R) return inf;
if(L<=l && r<=R) return mn[k];
pushdown(k);ll re=inf;
if(L<=mid) re=ask(lc,l,mid,L,R);
if(R>mid) re=min(re,ask(rc,mid+1,r,L,R));
return re;
}
inline void change(int x,int y,ll z)
{
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]1,1,n,in[top[x]],in[x],z);
}
if(d[x]1,1,n,in[y],in[x],z);
}
int main(){
int op,i,x,y;ll z;
rd(n);rd(m);
for(i=1;ifor(i=1;i<=n;++i) rd(a[i]);
dfs(1);dfss(1,1);
build(1,1,n);
rd(rt);
for(;m;--m){
rd(op);
if(op==1) rd(rt);
else if(op==2){
rd(x);rd(y);rd(z);
change(x,y,z);
}else{
rd(x);
if(x==rt) ans=ask(1,1,n,1,n);
else if((in[x]>=in[rt] && ot[x]<=ot[rt]) || (ot[x]ot[rt]))
ans=ask(1,1,n,in[x],ot[x]);
else{
y=rt;
for(;top[y]!=top[x] && f[top[y]]!=x;y=f[top[y]]);
if(top[x]==top[y]) y=son[x];else y=top[y];
ans=min(ask(1,1,n,1,in[y]-1),ask(1,1,n,ot[y]+1,n));
}
printf("%lld\n",ans);
}
}
}