遥远的国度
遥远的国度
题目描述
zcwwzdjn
在追杀 zhx
,而 zhx
逃入了一个遥远的国度。当 zcwwzdjn
准备进入遥远的国度继续追杀时,守护神 RapiD
阻拦了 zcwwzdjn
的去路,他需要 zcwwzdjn
完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有 \(n\) 个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,第 \(i\) 个的防御值为 \(val_i\),有些时候 RapiD
会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。
RapiD
想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。
由于 RapiD
无法解决这个问题,所以他拦住了 zcwwzdjn
希望他能帮忙。但 zcwwzdjn
还要追杀 zhx
,所以这个重大的问题就被转交到了你的手上。
输入格式
第 \(1\) 行两个整数 \(n\ m\),代表城市个数和操作数。
第 \(2\) 行至第 \(n\) 行,每行两个整数 \(u\ v\),代表城市 \(u\) 和城市 \(v\) 之间有一条路。
第 \(n+1\) 行,有 \(n\) 个整数,第 \(i\) 个代表第 \(i\) 个点的初始防御值 \(val_i\)。
第 \(n+2\) 行一个整数 \(id\),代表初始的首都为 \(id\)。
第 \(n+3\) 行至第 \(n+m+2\) 行,首先有一个整数 \(opt\)。
如果 \(opt=1\),接下来有一个整数 \(id\),代表把首都修改为 \(id\);
如果 \(opt=2\),接下来有三个整数 \(x\ y\ v\),代表将 \(x\ y\) 路径上的所有城市的防御值修改为 \(v\);
如果 \(opt=3\),接下来有一个整数 \(id\),代表询问以城市 \(id\) 为根的子树中的最小防御值。
输出格式
对于每个 \(opt=3\) 的操作,输出一行代表对应子树的最小点权值。
样例 #1
样例输入 #1
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
样例输出 #1
1
2
3
4
提示
对于 \(20\%\) 的数据,\(n\le 1000,m\le 1000\)。
对于另外 \(10\%\) 的数据,\(n\le 100000,m\le 100000\),保证修改为单点修改。
对于另外 \(10\%\) 的数据,\(n\le100000,m \le 100000\),保证树为一条链。
对于另外 \(10\%\) 的数据,\(n\le 100000,m\le100000\),没有修改首都的操作。
对于 \(100\%\) 的数据,\(1 \leq n\le 100000,1 \leq m \le 100000,0<val_i<2^{31}\)。
这题其实就考虑三种情况
root==p1
root在p1子树内
root在p1子树外
主要是第二种情况时,所以我们要找到它的公共祖先的孩子
inline int fd(int l,int r)
{
int ans=LONG_LONG_MAX;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
if(fa[top[l]]==r)return top[l];注意这一步一定是要加的,因为son[l]为重儿子,我们不一定是要去重儿子那条路
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
// cout<<l<<endl;
return son[l];
l为公共祖先
}
点击查看代码
#include <bits/stdc++.h>
//#define ll long long
#define int long long
#define rint int
#define mk make_pair
#define pb push_back
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N =3e5+5;
int n,cnt,head[N*2],w[N],rnk[N],dfn[N],dep[N],fa[N],son[N],top[N],size[N],ntime,m,root;
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-f;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
struct Edge
{
int u,to,w,next;
}edge[N*2];
void add(int u,int v,int w)
{
edge[++cnt].u=u;
edge[cnt].to=v;
edge[cnt].next=head[u];
edge[cnt].w=w;
head[u]=cnt;
}
struct Tree
{
int l,r;
int cnt,lz;
}st[N*4];
inline void pushup(int rt)
{
st[rt].cnt=min(st[lid].cnt,st[rid].cnt);
}
inline void pushdown(int rt)
{
if(st[rt].lz)
{
int lz=st[rt].lz;st[rt].lz=0;
st[lid].lz=lz;st[rid].lz=lz;
st[lid].cnt=lz;
st[rid].cnt=lz;
}
}
void bt(int rt,int l,int r)
{
st[rt].l=l;st[rt].r=r;
if(l==r)
{
st[rt].cnt=w[rnk[l]];
// cout<<"%%"<<rt<<" "<<st[rt].cnt<<endl;
return;
}
int mid=(l+r)>>1;
bt(lid,l,mid);bt(rid,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int val)
{
if(l<=st[rt].l&&st[rt].r<=r)
{
st[rt].cnt=val;
// cout<<rt<<" "<<val<<endl;;
st[rt].lz=val;
return;
}
pushdown(rt);
int mid=(st[rt].l+st[rt].r)>>1;
if(l<=mid)update(lid,l,r,val);
if(r>mid)update(rid,l,r,val);
pushup(rt);
}
int query(int rt,int l,int r)
{
if(l>r)return LONG_LONG_MAX;
if(l<=st[rt].l&&st[rt].r<=r)
{
return st[rt].cnt;
}
int mid=(st[rt].l+st[rt].r)>>1;
pushdown(rt);
int ans=LONG_LONG_MAX;
if(l<=mid)ans=min(query(lid,l,r),ans);
if(r>mid)ans=min(query(rid,l,r),ans);
return ans;
}
void ffind(int u,int _fa,int depth)
{
int ms=0;
fa[u]=_fa;
son[u]=0;
dep[u]=depth;
size[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int to=edge[i].to;
if(dep[to])continue;
ffind(to,u,depth+1);
size[u]+=size[to];
if(ms<size[to])
{
son[u]=to;
ms=size[to];
}
}
}
void connect(int u,int asct)
{
dfn[u]=++ntime;
top[u]=asct;
rnk[ntime]=u;
if(son[u])
{
connect(son[u],asct);
}
for(int i=head[u];i;i=edge[i].next)
{
int to=edge[i].to;
if(to==son[u]||to==fa[u])continue;
connect(to,to);
}
}
inline int Q(int l,int r,int rt)
{
int ans=LONG_LONG_MAX;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
ans=min(query(1,dfn[top[l]],dfn[l]),ans);
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
ans=min(query(1,dfn[l],dfn[r]),ans);
// cout<<l<<endl;
return ans;
}
inline int fd(int l,int r)
{
int ans=LONG_LONG_MAX;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
if(fa[top[l]]==r)return top[l];
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
// cout<<l<<endl;
return son[l];
}
inline void M(int l,int r,int val)
{
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
update(1,dfn[top[l]],dfn[l],val);
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
update(1,dfn[l],dfn[r],val);
}
signed main()
{
// ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen("P3979_3.in","r",stdin);
// freopen("aa.out","w",stdout);
cin>>n>>m;
int a,b;
for(int i=1;i<=n-1;i++)
{
a=read();b=read();
add(a,b,0);add(b,a,0);
}
for(int i=1;i<=n;i++)
{
w[i]=read();
}
ffind(1,0,1);
connect(1,1);
bt(1,1,n);
int op,p1,p2,v;
root=read();
for(int i=1;i<=m;i++)
{
op=read();
if(op==1)
{
root=read();
}else if(op==2)
{
p1=read();p2=read();v=read();
M(p1,p2,v);
}else
{
p1=read();
// cout<<"&&";
if(p1==root)
{
cout<<st[1].cnt<<endl;
}
else if(dfn[p1]<=dfn[root]&&dfn[root]<=dfn[p1]+size[p1]-1)
{
p1=fd(root,p1);
cout<<min(query(1,1,dfn[p1]-1),query(1,dfn[p1]+size[p1],n))<<endl;
}else
{
cout<<query(1,dfn[p1],dfn[p1]+size[p1]-1)<<endl;
}
}
}
return 0;
}