写这题的时候状态贼好,想了20min就想到正解了qwq
首先链上赋值没难度吧,直接树剖后打标记区间赋值维护一下区间最小就好了
然后考虑换根问题:
(ro为当前根,x为要求的子树的根)
1.当ro==x时,求全局最小
2.当lca(ro,x)!=x时,说明此时根在x的子树外,莫得影响
3.当lca(ro,x)==x时,说明此时根在x的子树内,倍增将ro将跳到x的son上,然后就查询出除son的子树外的最小
/**************************************************************
Problem: 3083
User: syh0313
Language: C++
Result: Accepted
Time:4996 ms
Memory:22800 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define lch a[n].lc
#define rch a[n].rc
using
namespace
std;
const
long
long
inf=100000000000;
const
int
maxn=100010;
int
n,m,root,ro,xx,topt,cnt;
struct
da{
int
lc,rc;
long
long
mi,tag;}a[maxn*4];
int
st[maxn<<1],nt[maxn<<1],to[maxn<<1];
int
dep[maxn],fa[maxn],rem[maxn],si[maxn];
int
top[maxn],dfn[maxn],dfn_num,line[maxn];
bool
f[maxn];
long
long
v[maxn];
void
add(
int
x,
int
y)
{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}
void
dfs1(
int
x,
int
de)
{
f[x]=1; dep[x]=de; si[x]=1;
int
p=st[x],ma=0;
while
(p)
{
if
(!f[to[p]])
{
dfs1(to[p],de+1);
si[x]+=si[to[p]];
fa[to[p]]=x;
if
(si[to[p]]>ma) {ma=si[to[p]]; rem[x]=to[p];}
}
p=nt[p];
}
}
void
dfs2(
int
x)
{
f[x]=1;
if
(rem[fa[x]]==x) top[x]=top[fa[x]];
else
top[x]=x;
dfn[x]=++dfn_num; line[dfn_num]=x;
int
p=st[x];
if
(rem[x]) dfs2(rem[x]);
while
(p)
{
if
(!f[to[p]]) dfs2(to[p]);
p=nt[p];
}
}
void
updata(
int
n){a[n].mi=min(a[lch].mi,a[rch].mi);}
void
build_tree(
int
&n,
int
l,
int
r)
{
n=++cnt;
if
(l==r) {a[n].mi=v[line[l]];
return
;}
int
mid=(l+r)>>1;
build_tree(lch,l,mid); build_tree(rch,mid+1,r);
updata(n);
}
void
pushdown(
int
n)
{
if
(!a[n].tag)
return
;
a[lch].mi=a[rch].mi=a[n].tag;
a[lch].tag=a[rch].tag=a[n].tag;
a[n].tag=0;
}
void
tree_fz(
int
n,
int
L,
int
R,
int
l,
int
r,
long
long
k)
{
if
(L==l && R==r) {a[n].mi=k; a[n].tag=k;
return
;}
int
mid=(L+R)>>1; pushdown(n);
if
(r<=mid) tree_fz(lch,L,mid,l,r,k);
else
if
(l>=mid+1) tree_fz(rch,mid+1,R,l,r,k);
else
tree_fz(lch,L,mid,l,mid,k),tree_fz(rch,mid+1,R,mid+1,r,k);
updata(n);
}
void
qfz(
int
x,
int
y,
long
long
k)
{
while
(top[x]!=top[y])
{
if
(dep[top[x]]<dep[top[y]]) swap(x,y);
tree_fz(root,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if
(dfn[x]>dfn[y]) swap(x,y);
tree_fz(root,1,n,dfn[x],dfn[y],k);
}
long
long
qury(
int
n,
int
L,
int
R,
int
l,
int
r)
{
if
(l>r)
return
inf;
if
(L==l && R==r)
return
a[n].mi;
int
mid=(L+R)>>1; pushdown(n);
if
(r<=mid)
return
qury(lch,L,mid,l,r);
else
if
(l>=mid+1)
return
qury(rch,mid+1,R,l,r);
else
return
min(qury(lch,L,mid,l,mid),qury(rch,mid+1,R,mid+1,r));
updata(n);
}
int
lca(
int
x,
int
y)
{
while
(top[x]!=top[y])
{
if
(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if
(dep[x]<dep[y])
return
x;
return
y;
}
int
find(
int
x,
int
y)
{
while
(fa[x]!=y)
{
if
(dep[fa[top[x]]]>dep[y]) x=fa[top[x]];
else
if
(dep[fa[top[x]]]==dep[y]) x=top[x];
else
x=rem[y];
}
return
x;
}
int
main()
{
scanf
(
"%d%d"
,&n,&m);
for
(
int
i=1;i<n;i++)
{
int
xx,yy;
scanf
(
"%d%d"
,&xx,&yy);
add(xx,yy); add(yy,xx);
}
for
(
int
i=1;i<=n;i++)
scanf
(
"%lld"
,&v[i]);
dfs1(1,1);
memset
(f,0,
sizeof
f); dfs2(1);
build_tree(root,1,n);
scanf
(
"%d"
,&ro);
while
(m--)
{
int
ff=0;
scanf
(
"%d"
,&ff);
if
(ff==1) {
scanf
(
"%d"
,&xx); ro=xx;}
else
if
(ff==2)
{
int
p1,p2;
long
long
vv;
scanf
(
"%d%d%lld"
,&p1,&p2,&vv);
qfz(p1,p2,vv);
}
else
if
(ff==3)
{
scanf
(
"%d"
,&xx);
int
lc=lca(ro,xx);
if
(ro==xx)
printf
(
"%lld\n"
,a[root].mi);
else
if
(lc!=xx)
printf
(
"%lld\n"
,qury(root,1,n,dfn[xx],dfn[xx]+si[xx]-1));
else
{
int
xxx=find(ro,xx);
printf
(
"%lld\n"
,min(qury(root,1,n,1,dfn[xxx]-1),qury(root,1,n,dfn[xxx]+si[xxx],n)));
}
}
}
return
0;
}