3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 512 MB
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
提示
对于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。
HINT
Source
zhonghaoxi提供
这题如果没有操作 1 1 1就是一个裸的树链剖分:操作 2 2 2路径修改,操作 3 3 3维护子树最小值。
那么在加入了操作
1
1
1之后,操作
2
2
2的部分显然没有发生变化
代码:
inline void change(int x,int y,long long v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,num[top[x]],num[x],v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
update(1,num[y],num[x],v);
}
其中 u p d a t e update update是指线段树的区间修改操作, n u m num num数组记录 d f s dfs dfs序。
所以我们只需要考虑换根对维护子树最小值信息的影响,那么我们可以分类讨论一波:
我们设当前询问的子树的根为 u u u,当前的根节点为 r o o t root root。
第一种情况: l c a lca lca( u u u, r o o t root root)!= u u u,那么我们发现在以 r o o t root root为根时 u u u原来的子树就是现在的子树,直接线段树区间查询。
第二种情况: u u u== r o o t root root,那么此时 u u u就是根节点,直接返回线段树根节点的 m i n min min值
第三种情况:
r
o
o
t
root
root在
u
u
u原来的子树内,即
l
c
a
lca
lca(
r
o
o
t
root
root,
u
u
u)==
u
u
u&&
u
u
u!=
r
o
o
t
root
root,怎么做呢?
我们找到
u
u
u在
r
o
o
t
root
root->
u
u
u这条链上
u
u
u的儿子
s
s
s,那么子树
s
s
s的补集就是我们查询的区间。
没有其他情况了
贴一发代码
#include<bits/stdc++.h>
#define N 100005
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline long long read(){
long long ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
return ans;
}
struct Node{int l,r;long long minn,lz;}T[N<<2];
struct node{int v,next;}e[N<<1];
long long a[N];
int first[N],dep[N],top[N],fa[N],hson[N],siz[N],num[N],pred[N],root,n,m,cnt=0,tot=0;
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline void dfs1(int p){
siz[p]=1,hson[p]=0;
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa[p])continue;
fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
inline void dfs2(int p,int tp){
top[p]=tp,num[p]=++tot,pred[tot]=p;
if(hson[p])dfs2(hson[p],tp);
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v!=fa[p]&&v!=hson[p])dfs2(v,v);
}
}
inline long long min(long long a,long long b){return a<b?a:b;}
inline void pushup(int p){T[p].minn=min(T[lc].minn,T[rc].minn);}
inline void pushnow(int p,long long v){T[p].minn=v,T[p].lz=v;}
inline void pushdown(int p){
if(T[p].lz==0)return;
pushnow(lc,T[p].lz),pushnow(rc,T[p].lz),T[p].lz=0;
}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].lz=0;
if(l==r){T[p].minn=a[pred[l]];return;}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
inline void update(int p,int ql,int qr,long long v){
if(T[p].l>qr||T[p].r<ql)return;
if(ql<=T[p].l&&T[p].r<=qr){pushnow(p,v);return;}
pushdown(p);
if(qr<=mid)update(lc,ql,qr,v);
else if(ql>mid)update(rc,ql,qr,v);
else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
pushup(p);
}
inline long long query(int p,int ql,int qr){
if(T[p].l>qr||T[p].r<ql)return 1e16;
if(ql<=T[p].l&&T[p].r<=qr)return T[p].minn;
pushdown(p);
if(qr<=mid)return query(lc,ql,qr);
if(ql>mid)return query(rc,ql,qr);
return min(query(lc,ql,mid),query(rc,mid+1,qr));
}
inline void change(int x,int y,long long v){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,num[top[x]],num[x],v);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
update(1,num[y],num[x],v);
}
inline 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]];
}
return dep[x]<dep[y]?x:y;
}
inline int fid(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
if(fa[top[x]]==y)return top[x];
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
return hson[y];
}
int main(){
n=read(),m=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
add(u,v),add(v,u);
}
for(int i=1;i<=n;++i)a[i]=read();
root=read();
dfs1(root);
dfs2(root,root);
build(1,1,n);
while(m--){
int op=read(),u=read();
if(op==1){root=u;continue;}
if(op==2){int v=read();long long w=read();change(u,v,w);continue;}
if(u==root){printf("%lld\n",T[1].minn);continue;}
int t=lca(u,root);
if(t!=u){printf("%lld\n",query(1,num[u],num[u]+siz[u]-1));continue;}
int s=fid(u,root);
printf("%lld\n",min(query(1,1,num[s]-1),query(1,num[s]+siz[s],n)));
}
return 0;
}