Description
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
1
2
3
4
Hint
【数据范围】
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
%%%huangziyue大佬%%%
网上树剖题解很不优美,要讨论3种情况,于是我很不负责任的贴一份lct解法的,因为会re一组至今无解o((⊙﹏⊙))o
lct维护子树信息——维护最小值,Tarjan似乎没想过要用lct维护子树信息,不过参照大融合,我们照样可以维护子树最值。
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int N = 1e5+7;
struct Splay{
int c[N];
bool rev[N];
int vl[N],Min[N];
multiset<int>s[N];//记录虚儿子
int p[N],ch[N][2];
int tmin[N],fmin[N];//tmin维护实儿子,fmin维护虚儿子
#define Ls(v) ch[v][0]
#define rs(v) ch[v][1]
inline bool isroot(int x){
return (Ls(p[x])^x)&&(rs(p[x])^x);
}
inline void pushdown(int x){
if(c[x]){
c[Ls(x)]=c[rs(x)]=c[x];
vl[x]=c[x];
c[x]=0;
}
if(rev[x]){
rev[Ls(x)]^=1,rev[rs(x)]^=1;
swap(Ls(x),rs(x));
rev[x]=0;
}
}
inline void maintain(int x){
tmin[x]=vl[x],fmin[x]=*(s[x].begin());
if(Ls(x))tmin[x]=min(tmin[x],tmin[Ls(x)]),fmin[x]=min(fmin[x],fmin[Ls(x)]);
if(rs(x))tmin[x]=min(tmin[x],tmin[rs(x)]),fmin[x]=min(fmin[x],fmin[rs(x)]);
Min[x]=min(tmin[x],fmin[x]);
}
inline void rot(int x){
int f=p[x],gf=p[f],type=rs(f)==x,son=ch[x][type^1];
if(isroot(f)^1)ch[gf][rs(gf)==f]=x;p[x]=gf;
ch[p[son]=f][type]=son,maintain(f);
ch[p[f]=x][type^1]=f,maintain(x);
}
int top,stk[N];
inline void splay(int x){
stk[++top]=x;
if(isroot(x)^1)for(int i=x;isroot(i)^1;i=p[i])stk[++top]=p[i];
while(top)pushdown(stk[top--]);
while(isroot(x)^1){
if(isroot(p[x]))return rot(x),void();
if((rs(p[p[x]])==p[x])==(rs(p[x])==x))rot(p[x]);
rot(x);
}
}
inline void init(int x,int v,int fa){
s[x].insert(fmin[x]=1<<30);
vl[x]=Min[x]=tmin[x]=v;
rev[x]=c[x]=0;
p[x]=fa;
}
};
struct LCT{
Splay sp;
inline void access(int x){
for(int lastx=0;x;lastx=x,x=sp.p[x]){
sp.splay(x);
if(sp.rs(x))sp.s[x].insert(sp.Min[sp.rs(x)]);
sp.rs(x)=lastx;
if(sp.rs(x))sp.s[x].erase(sp.s[x].find(sp.Min[sp.rs(x)]));
sp.maintain(x);
}
}
inline void makeroot(int x){
access(x),sp.splay(x),sp.rev[x]^=1;
}
inline void split(int x,int y){
makeroot(x),access(y),sp.splay(y);
}
}lct;
int n,m,Root,vl[N];
struct Edge{
int cnt,h[N],to[N<<1],next[N<<1];
inline void add(int x,int y){
next[++cnt]=h[x];
to[cnt]=y;
h[x]=cnt;
}
}e;
void dfs(int x,int fa){//害怕撑爆
lct.sp.init(x,vl[x],fa);
for(int p=e.h[x];p;p=e.next[p])if(e.to[p]^fa){
dfs(e.to[p],x);
lct.sp.s[x].insert(lct.sp.Min[e.to[p]]);
}
lct.sp.maintain(x);
}
inline void init(){
scanf("%d%d",&n,&m);
Inc(i,1,n-1){
int x,y;scanf("%d%d",&x,&y);
e.add(x,y),e.add(y,x);
}
Inc(i,1,n)scanf("%d",&vl[i]);
scanf("%d",&Root);
}
inline void solv(){
lct.makeroot(Root);
while(m--){
int op,x,y,z;scanf("%d",&op);
if(op==1)scanf("%d",&Root),lct.makeroot(Root);
else if(op==2){
scanf("%d%d%d",&x,&y,&z);
lct.split(x,y);
lct.sp.c[y]=z;
}else {
scanf("%d",&x);
lct.makeroot(Root),lct.access(x),lct.sp.splay(x);//实子树全为祖先
cout<<min(lct.sp.vl[x],*(lct.sp.s[x].begin()))<<"\n";
}
}
}
int main(){
init();
dfs(Root,0);
solv();
return 0;
}