P3979 遥远的国度

换根操作不用真的换根

发现只有子树操作有影响。

而且是修改的点是新根的祖先的时候有影响。

当前点往新根那个方向的子树都不能计算进去,其他全部计算即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<set>
#include<iomanip>
#include<ctime>
#include<cstdlib>
#include<cmath>
#define int long long
using namespace std;
#define orz cout<<"lyakioi!!!!!!!!!!!!!!!!!"<<endl
inline int r(){int s=0,k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){s=s*10+c-'0';c=getchar();}return s*k;}
int cnt,son[1000001],n,m,head[1000001],deep[1000001],fa[1000001],size[1000001],tr[1000001],la[1000001],id[1000001],w[1000001],nw[1000001],root,times,top[1000001];
struct node
{
	int to,next;
}a[1000001];
void add_edge(int from,int to)
{
	a[++cnt].to=to;
	a[cnt].next=head[from];
	head[from]=cnt;
}
void dfs1(int u,int father,int deeps)
{
	deep[u]=deeps;
	fa[u]=father;
	size[u]=1;
	int maxi=0;
	for(int i=head[u];i;i=a[i].next)
	{
		int v=a[i].to;
		if(v==father)continue;
		dfs1(v,u,deeps+1);
		size[u]+=size[v];
		if(maxi<size[v])
		{
			son[u]=v;
			maxi=size[v];
		}
	}
}
void dfs2(int u,int tp)
{
	times++;
	id[u]=times;
	top[u]=tp;
	nw[times]=w[u];
	if(son[u])dfs2(son[u],tp);
	
	for(int i=head[u];i;i=a[i].next)
	{
		int v=a[i].to;
		if(!id[v])dfs2(v,v);
	}
}
void push_down(int bh,int k)
{
	tr[bh]=la[bh]=k;
}
void build(int l,int r,int bh)
{
	if(l==r)
	{
		tr[bh]=nw[l];
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,bh*2);
	build(mid+1,r,bh*2+1);
	tr[bh]=min(tr[bh*2],tr[bh*2+1]);
}
void tr_add(int now_l,int now_r,int bh,int l,int r,int k)
{
	if(l<=now_l&&now_r<=r)
	{
		push_down(bh,k);
		return;
	}
	if(now_l>r||now_r<l)return;
	int mid=(now_l+now_r)/2;
	if(la[bh])
	{
		push_down(bh*2,la[bh]);
		push_down(bh*2+1,la[bh]);
		la[bh]=0;
	}
	tr_add(now_l,mid,bh*2,l,r,k);
	tr_add(mid+1,now_r,bh*2+1,l,r,k);
	tr[bh]=min(tr[bh*2],tr[bh*2+1]);
}
int sum(int now_l,int now_r,int bh,int l,int r)
{
	if(l<=now_l&&now_r<=r)return tr[bh];
	if(now_l>r||now_r<l)return 1e18;
	int mid=(now_l+now_r)/2;
	if(la[bh])
	{
		push_down(bh*2,la[bh]);
		push_down(bh*2+1,la[bh]);
		la[bh]=0;
	}
	return min(sum(now_l,mid,bh*2,l,r),sum(mid+1,now_r,bh*2+1,l,r));
}
void add(int x,int y,int w)
{
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		tr_add(1,n,1,id[top[x]],id[x],w);
		x=top[x];x=fa[x];
	}
	if(deep[x]<deep[y])swap(x,y);
	tr_add(1,n,1,id[y],id[x],w);
}
signed main()
{
	int x,y,z,opt,newroot;
	n=r();m=r();
	for(int i=1;i<n;i++)
	{
		x=r();y=r();
		add_edge(x,y);
		add_edge(y,x);
	}
	for(int i=1;i<=n;i++)w[i]=r();
	root=r();newroot=root;
	dfs1(root,0,1);
	dfs2(root,root);
//	for(int i=1;i<=n;i++)cout<<"ah"<<nw[i]<<endl;
	build(1,n,1);
//	cout<<"??"<<tr[1]<<endl;
	for(int i=1;i<=m;i++)
	{
		opt=r();
		if(opt==1)newroot=r();
		else if(opt==2)
		{
			x=r();y=r();z=r();
			add(x,y,z);
		}
		else
		{
			int ans=0;
			x=r();
			if(x==newroot)ans=tr[1];
			else if(id[x]<id[newroot]&&id[newroot]<=id[x]+size[x]-1)
			{
				for(int i=head[x];i;i=a[i].next)
				{
					int v=a[i].to;
					if(v==fa[x])continue;
					if(id[v]<=id[newroot]&&id[newroot]<=id[v]+size[v]-1)
					{
						ans=min(sum(1,n,1,1,id[v]-1),sum(1,n,1,id[v]+size[v],n));
						break;
					}
				}
			}
			else ans=sum(1,n,1,id[x],id[x]+size[x]-1);
			cout<<ans<<endl;
		}
	}
}
posted @ 2021-09-03 18:57  lei_yu  阅读(18)  评论(0编辑  收藏  举报