题意
给定一棵有根树,支持3种操作:
1.把首都修改为id;
2.将p1 p2路径上的所有城市的防御值修改为v;
3.询问以城市id为根的子树中的最小防御值。
分析
画了一堆图之后终于搞懂了一点点,首先换根的话肯定不是真的换。对于每次询问,设现在的根为root,准备询问的结点为x。来考虑几种情况。
1.root == x ,询问整棵树,直接输出全集。
2.root不为x的子树,则直接考虑x的整棵子树。
3.root为x的子树(也可能是x的某子树中的结点),则不能考虑x的这棵子树,就直接抹去这一段考虑其补集,边界条件的话要注意,不然可能RE。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define Rep(i,s,t) for(int i=s;i<=t;i++)
#define For(i,s,t) for(int i=s;i;i=t)
using namespace std;
const int maxx = 100000 + 25;
const int Inf = (unsigned)(-1) >> 1;
int head[maxx],nxt[maxx<<1],to[maxx<<1];
int top[maxx],rnk[maxx],size[maxx],ftr[maxx],son[maxx],dpt[maxx];
int a[maxx],T[maxx<<2],Add[maxx<<2],fnl[maxx];
int n,m,num,f,cnt,x,y,z,root;
namespace Y{
void Ins(int x,int y){to[++num]=y;nxt[num]=head[x];head[x]=num;}
void Dfs1(int x){
size[x] = 1;
For( i , head[x] , nxt[i] ){
int now = to[i];if(now == ftr[x]) continue;
ftr[now] = x;dpt[now] = dpt[x] + 1;
Dfs1(now);size[x] += size[now];
if(size[now] > size[son[x]]) son[x] = now;
}
}
void Dfs2(int x,int brn){
rnk[x] = ++cnt;top[x] = brn;
if(son[x]) Dfs2(son[x],brn);
For( i , head[x] , nxt[i] )
if(to[i] != ftr[x] && to[i] != son[x])
Dfs2(to[i],to[i]);
fnl[x] = cnt;
}
void pushdown(int i){
T[i<<1] = T[i<<1|1] = Add[i<<1] = Add[i<<1|1] = Add[i];
Add[i] = 0;
}
void modify(int i,int x,int y,int l,int r,int k){
if(x<=l && r<=y) {T[i] = Add[i] = k;return;}
if(Add[i]) pushdown(i);int mid = (l+r) >> 1;
if(x <= mid) modify(i<<1,x,y,l,mid,k);
if(y > mid) modify(i<<1|1,x,y,mid+1,r,k);
T[i] = min(T[i<<1],T[i<<1|1]);
}
int Query(int i,int x,int y,int l,int r){
if(x<=l && r<=y) return T[i];int ans = Inf;
if(Add[i]) pushdown(i);int mid = (l+r) >> 1;
if(x <= mid) ans = min(ans,Query(i<<1,x,y,l,mid));
if(y > mid) ans = min(ans,Query(i<<1|1,x,y,mid+1,r));
return ans;
}
void update(int x,int y,int k){
while(top[x] != top[y]){
if(dpt[top[x]] > dpt[top[y]]) x^=y^=x^=y;
modify(1,rnk[top[y]],rnk[y],1,n,k);
y = ftr[top[y]];
}
if(rnk[x] > rnk[y]) x^=y^=x^=y;
modify(1,rnk[x],rnk[y],1,n,k);
}
int Get(int x){
if(x == root) return Query(1,1,n,1,n);
if(rnk[root] < rnk[x] || rnk[root] > fnl[x])
return Query(1,rnk[x],fnl[x],1,n);
int ans = Inf,i;
for(i=head[x];i;i=nxt[i])
if(to[i] != ftr[x] && rnk[root] >= rnk[to[i]] && rnk[root] <= fnl[to[i]])
break;
ans = min(ans,Query(1,1,rnk[to[i]]-1,1,n));
if(fnl[to[i]] != n)
ans = min(ans,Query(1,fnl[to[i]]+1,n,1,n));
return ans;
}
}
using namespace Y;
int main(){
scanf("%d%d",&n,&m);
Rep( i , 1 , n-1 ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
Rep( i , 1 , n ) scanf("%d",&a[i]);
scanf("%d",&root);Dfs1(root),Dfs2(root,root);
Rep( i , 1 , n ) modify(1,rnk[i],rnk[i],1,n,a[i]);
while( m-- ){
scanf("%d",&f);
if(f == 1) scanf("%d",&z),root = z;
if(f == 2) scanf("%d%d%d",&x,&y,&z),update(x,y,z);
if(f == 3) scanf("%d",&x),printf("%d\n",Get(x));
}
return 0;
}