遙遠的國度
題目描述
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;
}