返回顶部

遥远的国度

遥远的国度

题目描述

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;
}
posted @ 2024-05-21 11:50  wlesq  阅读(10)  评论(0编辑  收藏  举报