和我做过的另外一个BZOJ题很像,但是忘了题号了……BZOJ3306 题解
换根就是针对当前根找到子树然后容斥一下
注意dfs序中一棵树的子树一定是连续的
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,a[N],id[N],pre[N],segn,en,h[N],root,siz[N],son[N],dep[N],fa[N],top[N],OPTION;
struct Edge{
int b,next;
}e[N<<1];
void AddEdge(int sa,int sb){
e[++en].b=sb;
e[en].next=h[sa];
h[sa]=en;
}
struct SegTree{
int l,r,mn,tag;
}tree[N<<2];
void Pushdown(int rt){
if(tree[rt].tag){
tree[rt<<1].tag=tree[rt].tag;
tree[rt<<1|1].tag=tree[rt].tag;
tree[rt<<1].mn=tree[rt].tag;
tree[rt<<1|1].mn=tree[rt].tag;
tree[rt].tag=0;
}
}
void Pushup(int rt){
tree[rt].mn=min(tree[rt<<1].mn,tree[rt<<1|1].mn);
}
void Build(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
if(l==r){tree[rt].mn=a[pre[l]];return;}
int mid=l+r>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
Pushup(rt);
}
void Modify(int rt,int l,int r,int x){
if(l<=tree[rt].l && tree[rt].r<=r){tree[rt].mn=x;tree[rt].tag=x;return;}
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(l<=mid)Modify(rt<<1,l,r,x);
if(r>mid)Modify(rt<<1|1,l,r,x);
Pushup(rt);
}
int Query(int rt,int l,int r){
if(l<=tree[rt].l && tree[rt].r<=r)return tree[rt].mn;
Pushdown(rt);
int mid=tree[rt].l+tree[rt].r>>1;
if(r<=mid)return Query(rt<<1,l,r);
else if(l>mid)return Query(rt<<1|1,l,r);
else return min(Query(rt<<1,l,r),Query(rt<<1|1,l,r));
}
void dfs1(int u,int fat){
siz[u]=1;
dep[u]=dep[fat]+1;
son[u]=0;
fa[u]=fat;
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(v==fat)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int ux){
top[u]=ux;
id[u]=++segn;
pre[segn]=u;
if(son[u])dfs2(son[u],ux);
else return;
for(int i=h[u];i;i=e[i].next){
int v=e[i].b;
if(son[u]==v || fa[u]==v)continue;
dfs2(v,v);
}
}
void Change(int x,int y,int v){
int topx=top[x],topy=top[y];
while(topx!=topy){
if(dep[topx]<dep[topy]){swap(topx,topy);swap(x,y);}
Modify(1,id[topx],id[x],v);
x=fa[topx];
topx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
Modify(1,id[x],id[y],v);
}
int Ask(int Id){
if(root==Id)return Query(1,1,n);
int x=root,y=Id,topx=top[x],topy=top[y];
while(topx!=topy){
if(dep[topx]<dep[topy]){swap(topx,topy);swap(x,y);}
x=fa[topx];
topx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
if(x!=Id)return Query(1,id[Id],id[Id]+siz[Id]-1);
else {
for(int i=h[Id];i;i=e[i].next){
int v=e[i].b;
if(fa[Id]==v)continue;
if(id[v]<=id[root] && id[root]<=id[v]+siz[v]-1){
int mn=Query(1,id[1],id[v]-1);
if(id[v]+siz[v]-1!=n)mn=min(mn,Query(1,id[v]+siz[v],n));
return mn;
}
}
}
}
void Read(int &x){
char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=x*10+ch-'0';
}
int main(){
freopen("3083.in","r",stdin);
freopen("3083.out","w",stdout);
Read(n);Read(m);
for(int i=1;i<n;i++){int u,v;Read(u);Read(v);AddEdge(u,v);AddEdge(v,u);}
for(int i=1;i<=n;i++)Read(a[i]);
Read(root);
dfs1(1,0);
dfs2(1,1);
Build(1,1,n);
while(m--){
int opt,x,y,v;
Read(opt);
if(opt==1){Read(x);root=x;}
if(opt==2){Read(x);Read(y);Read(v);Change(x,y,v);}
if(opt==3){Read(x);printf("%d\n",Ask(x));}
}
return 0;
}