[BZOJ3083]遥远的国度

bzoj
luogu

题意

给你一棵树,每个点有点权,支持三种操作:
1、换根。
2、路径全部改成某一个数。
3、查询子树最小值。

sol

\(LCT?\)naive了吧。
考虑换根对子树形态的影响。对于原树中的父子关系而言(以\(1\)为根的树),当根不在询问点的子树中时,询问点的子树和在原树中的子树是相同的。
当询问点和根重合时,显然答案就是整棵树的答案。
当询问点是根的祖先(根在询问点的子树中)时,答案应该就是原树去掉根所在的询问点的那个儿子这棵子树的答案。
所以直接树剖维护即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
ll gi()
{
	ll x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 2e5+5;
int n,m,to[N<<1],nxt[N<<1],head[N],cnt,root;
int fa[N],dep[N],sz[N],son[N],top[N],dfn[N],low[N],ref[N];
ll val[N],t[N<<2],tag[N<<2];
void link(int u,int v)
{
	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void dfs1(int u,int f)
{
	fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
	for (int e=head[u];e;e=nxt[e])
		if (to[e]!=f)
		{
			dfs1(to[e],u);
			sz[u]+=sz[to[e]];
			if (sz[to[e]]>sz[son[u]]) son[u]=to[e];
		}
}
void dfs2(int u,int up)
{
	top[u]=up;dfn[u]=++cnt;ref[cnt]=u;
	if (son[u]) dfs2(son[u],up);
	for (int e=head[u];e;e=nxt[e])
		if (to[e]!=fa[u]&&to[e]!=son[u])
			dfs2(to[e],to[e]);
	low[u]=cnt;
}
bool inside(int u,int v){return dfn[v]<=dfn[u]&&dfn[u]<=low[v];}
int jump(int u,int v)
{
	int gg=u;
	while (top[u]^top[v])
		gg=top[u],u=fa[top[u]];
	return u==v?gg:son[v];
}
void build(int x,int l,int r)
{
	if (l==r) {t[x]=val[ref[l]];return;}
	int mid=l+r>>1;
	build(x<<1,l,mid);build(x<<1|1,mid+1,r);
	t[x]=min(t[x<<1],t[x<<1|1]);
}
void cover(int x,ll v){t[x]=tag[x]=v;}
void pushdown(int x)
{
	if (tag[x])
	{
		cover(x<<1,tag[x]);cover(x<<1|1,tag[x]);
		tag[x]=0;
	}
}
void modify(int x,int l,int r,int ql,int qr,ll v)
{
	if (l>=ql&&r<=qr) {cover(x,v);return;}
	pushdown(x);int mid=l+r>>1;
	if (ql<=mid) modify(x<<1,l,mid,ql,qr,v);
	if (qr>mid) modify(x<<1|1,mid+1,r,ql,qr,v);
	t[x]=min(t[x<<1],t[x<<1|1]);
}
ll query(int x,int l,int r,int ql,int qr)
{
	if (l>=ql&&r<=qr) return t[x];
	pushdown(x);int mid=l+r>>1;
	if (qr<=mid) return query(x<<1,l,mid,ql,qr);
	if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
	return min(query(x<<1,l,mid,ql,qr),query(x<<1|1,mid+1,r,ql,qr));
}
int main()
{
	n=gi();m=gi();
	for (int i=1;i<n;++i)
	{
		int u=gi(),v=gi();
		link(u,v);link(v,u);
	}
	cnt=0;dfs1(1,0);dfs2(1,1);
	for (int i=1;i<=n;++i) val[i]=gi();
	build(1,1,n);root=gi();
	while (m--)
	{
		int opt=gi();
		if (opt==1) root=gi();
		if (opt==2)
		{
			int u=gi(),v=gi();ll w=gi();
			while (top[u]^top[v])
			{
				if (dep[top[u]]<dep[top[v]]) swap(u,v);
				modify(1,1,n,dfn[top[u]],dfn[u],w);
				u=fa[top[u]];
			}
			if (dep[u]>dep[v]) swap(u,v);
			modify(1,1,n,dfn[u],dfn[v],w);
		}
		if (opt==3)
		{
			int x=gi();
			if (root==x) printf("%lld\n",t[1]);
			else if (inside(root,x))
			{
				int gg=jump(root,x);ll ans=query(1,1,n,dfn[x],dfn[x]);
				if (dfn[gg]>1) ans=min(ans,query(1,1,n,1,dfn[gg]-1));
				if (low[gg]<n) ans=min(ans,query(1,1,n,low[gg]+1,n));
				printf("%lld\n",ans);
			}
			else printf("%lld\n",query(1,1,n,dfn[x],low[x]));
		}
	}
	return 0;
}
posted @ 2018-04-12 16:49  租酥雨  阅读(251)  评论(3编辑  收藏  举报