遙遠的國度

wlesq發表於2024-05-21

遙遠的國度

題目描述

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;
}

相關文章