题目大意:给定一棵有根树,每个点有一个权值,提供三种操作:
1.将x节点变为根节点
2.将x到y路径上的点的权值全部改为v
3.询问x的子树中点权的最小值
树链剖分没商量!不过由于是查询子树的最小权值,所以我们选择DFS序剖分,而不是先前的轻重链剖分
即每个节点第一个遍历到的儿子是亲儿子 重标号就是DFS序
↑请无视本沙茶的一本道……轻重链剖分本来就能修改子树,我一直以来写的都是沙茶版……特此更正,希望大家别被我这个沙茶误导了
然后就好办了 换根的话不用真的换 只需要记录当前的根节点 然后求解时分三种情况讨论
1.root在x的子树中但不为x 此时枚举x的子节点y 若root在y的子树中 则求子树y的补集
2.root=x x是根节点 x的子树就是整棵树 此时直接输出全集
3.root不在x的子树中 此时直接输出x的子树的最小权值即可
很好写的一道题,挂了一下午。。。。。RE了三遍,干掉三个BUG,然后发现原来是freopen没删。。。交上去还是WA,这时发现少讨论第二种情况。。
最后写完是4000-MS。。。 今天是肿了么怎么写的这么惨。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls tree[p].lson
#define rs tree[p].rson
#define M 100100
using namespace std;
struct Tree{
int num,mark;
int lson,rson;
}tree[M<<1];
struct abcd{
int to,next;
}table[M<<1];
int head[M],tot;
int n,m,root,treetot,f[M],fa[M],dpt[M],top[M],son[M],pos[M],last[M],posf[M],cnt;
void add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void dfs(int x)
{
int i,lastson=0;
dpt[x]=dpt[fa[x]]+1;
pos[x]=++cnt;
if(son[fa[x]]==x)
top[x]=top[fa[x]];
else
top[x]=x;
for(i=head[x];i;i=table[i].next)
{
if(table[i].to==fa[x])
continue;
fa[table[i].to]=x;
if(!son[x])
son[x]=table[i].to;
lastson=table[i].to;
dfs(table[i].to);
}
if(lastson)
last[x]=last[lastson];
else
last[x]=pos[x];
}
void Build_Tree(int p,int x,int y)
{
int mid=x+y>>1;
if(x==y)
{
tree[p].num=posf[mid];
return ;
}
ls=++treetot;rs=++treetot;
Build_Tree(ls,x,mid);
Build_Tree(rs,mid+1,y);
tree[p].num=min(tree[ls].num,tree[rs].num);
}
void update(int p,int x,int y,int l,int r,int v)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
tree[p].num=tree[p].mark=v;
return ;
}
if(tree[p].mark)
{
tree[ls].num=tree[ls].mark=tree[p].mark;
tree[rs].num=tree[rs].mark=tree[p].mark;
tree[p].mark=0;
}
if(r<=mid) update(ls,x,mid,l,r,v);
else if(l>mid) update(rs,mid+1,y,l,r,v);
else update(ls,x,mid,l,mid,v),update(rs,mid+1,y,mid+1,r,v);
tree[p].num=min(tree[ls].num,tree[rs].num);
}
void change(int x,int y,int z)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dpt[fx]<dpt[fy])
swap(x,y),swap(fx,fy);
update(0,1,n,pos[fx],pos[x],z);
x=fa[fx];fx=top[x];
}
if(dpt[x]<dpt[y])
swap(x,y);
update(0,1,n,pos[y],pos[x],z);
}
int getans(int p,int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
return tree[p].num;
if(tree[p].mark)
{
tree[ls].num=tree[ls].mark=tree[p].mark;
tree[rs].num=tree[rs].mark=tree[p].mark;
tree[p].mark=0;
}
if(r<=mid) return getans(ls,x,mid,l,r);
else if(l>mid) return getans(rs,mid+1,y,l,r);
else return min( getans(ls,x,mid,l,mid) , getans(rs,mid+1,y,mid+1,r) );
}
int query(int x)
{
if(x==root)
return getans(0,1,n,1,n);
if(pos[root]<pos[x]||pos[root]>last[x])
return getans(0,1,n,pos[x],last[x]);
int i,re=0x7fffffff;
for(i=head[x];i;i=table[i].next)
if(pos[root]>=pos[table[i].to]&&pos[root]<=last[table[i].to]&&table[i].to!=fa[x])
break;
re=min(re,getans(0,1,n,1,pos[table[i].to]-1));
if(last[table[i].to]!=n)
re=min(re,getans(0,1,n,last[table[i].to]+1,n));
return re;
}
int main()
{
int i,x,y,z,p;
cin>>n>>m;
for(i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
for(i=1;i<=n;i++)
scanf("%d",&f[i]);
cin>>root;
dfs(root);
for(i=1;i<=n;i++)
posf[pos[i]]=f[i];
Build_Tree(0,1,n);
for(i=1;i<=m;i++)
{
scanf("%d",&p);
if(p==1)
scanf("%d",&root);
else if(p==2)
scanf("%d%d%d",&x,&y,&z),change(x,y,z);
else
scanf("%d",&x),printf("%d\n",query(x));
}
}