「洛谷P3979」遥远的国度

image
image
\({link}\)

分析:

树剖换根

换根有\(3\)种情况:

  • \(x=root\) 那么就是全局最小值
  • \(x\)不在\(1->root\)路径上 就是普通的查询
  • \(x\)\(1->root\)路径上 找出\(x\)的儿子\(k\)\(root\)为根时 \(x\)子树覆盖的其余位置 就是\(k\)\(k\)的子树

把这一部分单独计算 与\(x\)子树取\(min\)即可

CODE:

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+5,inf=0x7fffffff;
int n,T,w[N],root,tot,head[N];
int top[N],size[N],son[N],fa[N],id,dfn[N],dep[N],f[N];
struct SegmentTree{
	int val,lazy;
}tree[N<<2];
struct node{
	int to,next;
}a[N<<1];
void add(int x,int y)
{
	a[++tot]=(node){y,head[x]};
	head[x]=tot;
}
void up(int x){tree[x].val=min(tree[x<<1].val,tree[x<<1|1].val);}
void down(int x)
{
	tree[x<<1].lazy=tree[x].lazy;
	tree[x<<1|1].lazy=tree[x].lazy;
	tree[x<<1].val=tree[x].lazy;
	tree[x<<1|1].val=tree[x].lazy;
	tree[x].lazy=0;
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		tree[x].val=w[f[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	up(x);
}
void update(int x,int l,int r,int L,int R,int k)
{
	if(L<=l&&r<=R)
	{
		tree[x].lazy=k;
		tree[x].val=k;
		return;
	}
	int mid=(l+r)>>1;
	if(tree[x].lazy) down(x);
	if(L<=mid) update(x<<1,l,mid,L,R,k);
	if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
	up(x);
}
int query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tree[x].val;
	int mid=(l+r)>>1,res=inf;
	if(tree[x].lazy) down(x);
	if(L<=mid) res=min(res,query(x<<1,l,mid,L,R));
	if(mid<R) res=min(res,query(x<<1|1,mid+1,r,L,R));
	up(x);
	return res;
}
void Update(int x,int y,int k)
{
	while(top[x]^top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update(1,1,n,dfn[top[x]],dfn[x],k);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	update(1,1,n,dfn[x],dfn[y],k);
} 
int Op(int x)
{
	if(x==root) return -1;
	if(dfn[x]>=dfn[root]) return 0;
	else if(dfn[x]+size[x]-1<dfn[root]) return 0;
	int qwq=root;
	while(top[x]^top[qwq])
	{
		if(fa[top[qwq]]==x) return top[qwq];
		qwq=fa[top[qwq]];
	}
	return son[x];
}
int Query(int x)
{
	int op=Op(x);
	if(op==-1) return tree[1].val;
	else if(op==0) return query(1,1,n,dfn[x],dfn[x]+size[x]-1);
	else
	{
		int res=query(1,1,n,1,dfn[op]-1);
		if(dfn[op]+size[op]-1!=n) res=min(res,query(1,1,n,dfn[op]+size[op]-1,n));
		return res;
	}
}
void dfs(int x,int father,int deep)
{
	dep[x]=deep;
	fa[x]=father;
	size[x]=1;
	int numson=-1;
	for(int i=head[x];i;i=a[i].next)
	{
		int qwq=a[i].to;
		if(qwq==father) continue;
		dfs(qwq,x,deep+1);
		size[x]+=size[qwq];
		if(size[qwq]>numson)
			numson=size[qwq],son[x]=qwq;
	}
}
void dfs2(int x,int topN)
{
	top[x]=topN;
	dfn[x]=++id;
	f[id]=x;
	if(!son[x]) return;
	dfs2(son[x],topN);
	for(int i=head[x];i;i=a[i].next)
	{
		int qwq=a[i].to;
		if(qwq==fa[x]||qwq==son[x]) continue;
		dfs2(qwq,qwq);
	}
}
int main(){
	scanf("%d%d",&n,&T);
	for(int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	dfs(1,0,1);
	dfs2(1,1);
	build(1,1,n);
	scanf("%d",&root);
	while(T--)
	{
		int op;
		scanf("%d",&op);
		if(op==1) scanf("%d",&root);
		if(op==2)
		{
			int x,y,k;
			scanf("%d%d%d",&x,&y,&k);
			Update(x,y,k);
		}
		if(op==3)
		{
			int x;
			scanf("%d",&x);
			printf("%d\n",Query(x));
		}
	}
	return 0;
}
posted @ 2022-01-21 11:56  EschatonRin  阅读(6)  评论(0)    收藏  举报