P3979 遙遠的國度(換根樹剖)

issue敲膩害發表於2020-10-02

遙遠的國度

肯定不可能對每次換根重新樹剖一次

那就是隻以根 1 1 1剖一次來換根

其中 r o o t root root表示當前的根, u u u表示詢問 u u u子樹內的最小值

分情況討論

Ⅰ . 若 u = = r o o t Ⅰ.若u==root .u==root,明顯所輸出 a [ 1 ] a[1] a[1],全域性最小值

Ⅱ . 若 u 的 深 度 大 於 r o o t 且 u 在 1 到 r o o t 的 鏈 上 , 那 麼 開 始 換 根 Ⅱ.若u的深度大於root且u在1到root的鏈上,那麼開始換根 .urootu1root,

此 時 我 們 找 到 在 r o o t 到 u 的 鏈 上 的 v 是 u 的 直 系 兒 子 此時我們找到在root到u的鏈上的v是u的直系兒子 rootuvu

除 掉 以 v 為 根 子 樹 的 影 響 就 是 答 案 ( 由 於 子 樹 編 號 連 續 , 所 以 很 好 求 ) 除掉以v為根子樹的影響就是答案(由於子樹編號連續,所以很好求) v(,)

Ⅲ . 剩 下 的 情 況 , 相 當 於 換 根 沒 影 響 , 直 接 查 詢 Ⅲ.剩下的情況,相當於換根沒影響,直接查詢 .,,

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10; 
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define int long long
const int inf=1e15;
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1,num,n;
void add(int u,int v){
	d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
int laz[maxn],w[maxn],ww[maxn],root=1;
int deep[maxn],fa[maxn][25],siz[maxn],son[maxn],id[maxn],top[maxn],a[maxn];
void dfs1(int u,int f)
{
	deep[u]=deep[f]+1,  siz[u]=1;
	for(int i=1;i<=log2(n);i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;	if( v==f )	continue;
		fa[v][0]=u;
		dfs1(v,u);
		siz[u]+=siz[v];
		if( siz[son[u]]<siz[v] )	son[u]=v;
	}
}
int getfa(int x,int k)
{
	for(int i=log2(n);i>=0;i--)
		if( k&(1<<i) )	x=fa[x][i];
	return x;
}
void dfs2(int u,int topf)
{
	top[u]=topf, id[u]=++num, ww[num]=w[u];
	if( son[u] )	dfs2(son[u],topf);
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( v==son[u]||v==fa[u][0] )	continue;
		dfs2(v,v);
	}
}
void build(int rt,int l,int r)
{
	if( l==r ){ a[rt]=ww[l]; return; }
	build(lson); build(rson);
	a[rt] = min( a[ls],a[rs] );
}
void push_down(int rt)
{
	if( laz[rt]==0 )	return;
	laz[ls]=laz[rt], laz[rs]=laz[rt];
	a[ls]=laz[rt], a[rs]=laz[rt];
	laz[rt]=0;
}
void insert(int rt,int l,int r,int L,int R,int val)
{
	if( l>=L&&r<=R ){ laz[rt]=val; a[rt]=val; return; }
	if( r<L||l>R )	return;
	push_down(rt);
	insert(lson,L,R,val); insert(rson,L,R,val);
	a[rt] = min( a[ls],a[rs] );
}
int query(int rt,int l,int r,int L,int R)
{
	if( l>=L&&r<=R )	return a[rt];
	if( r<L||l>R )	return inf;
	push_down(rt);
	return min( query(lson,L,R),query(rson,L,R) );
}
int lca(int l,int r)
{
  	while( top[l]!=top[r] )
	{
  		if(deep[top[l]]<deep[top[r]]) swap(l,r);
  		l=fa[top[l]][0];
    }
  	return deep[l]<deep[r]?l:r;
}
int find(int u)
{
	int v;
	if( u==root )	return a[1];//就是全域性最小值 
	if( deep[u]<deep[root]&&fa[v=getfa(root,deep[root]-deep[u]-1)][0]==u )//在鏈上 
	{
		u=v;
		int ans=query(1,1,n,1,id[u]-1);
		ans = min( ans,query(1,1,n,id[u]+siz[u],n) );
		return ans;
	}
	else
		return	query(1,1,n,id[u],id[u]+siz[u]-1);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int q; cin >> n >> q;
	for(int i=1;i<n;i++)
	{
		int l,r; cin >> l >> r;
		add(l,r); add(r,l);
	}
	for(int i=1;i<=n;i++)	cin >> w[i];
	dfs1(1,0); dfs2(1,1);
	cin >> root;
	build(1,1,n);
	while( q-- )
	{
		int type,l,r,val;
		cin >> type;
		if( type == 1 )	cin >> root;
		else if( type==2 )
		{
			cin >> l >> r >> val;
			while( top[l]!=top[r] )
			{
				if( deep[top[l]]<deep[top[r]] )	swap(l,r);
				insert(1,1,n,id[top[l]],id[l],val);
				l=fa[top[l]][0];
			}
			if( deep[l]>deep[r] )	swap(l,r);
			insert(1,1,n,id[l],id[r],val);
		}
		else
		{
			cin >> l;//求l子樹內的最小值 
			cout << find(l) << endl;
		}
	}
}

相關文章