【BZOJ 3083】遥远的国度

BZOJ 3083 遥远的国度

这题的与 HAOI 2015T2 的不同点在于其有换根操作,但按照普通的思路我们可以发现,换根之后树的形态会有改变,每个节点的子树会发生改变,所以我们来分类讨论。

修改链的操作不会发生改变,现在只考虑子树minn。为了方便,我们定义现在的换的“根节点”为root(但实际上树的根节点为1),子树根为x,黑圈标明查询范围;

情况一   x=root,很显然此时应当查询整棵树。


情况二 lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关。

情况三,lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集

可以发现v一定在root到x的链上,且一定是x在这条链上的儿子,倍增法可以求得v

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r)/2
#define lch i<<1,l,mid
#define rch i<<1|1,mid+1,r
#define inf 2147483647
using namespace std;
struct hp{
	int fat,dep,size,wson,top,ls,rs;
	int lca[18];
}tree[100001];
struct hq{
	int u,v;
}a[200001];
struct hr{
	int minn,delta;
}seg[400001];
int point[100001],next[100001];
int val[400001],plc[100001];
int n,m,ans,e=1,totw=0,root;
void add(int x,int y)
{
	e++; a[e].u=x; a[e].v=y; next[e]=point[x]; point[x]=e;
	e++; a[e].u=y; a[e].v=x; next[e]=point[y]; point[y]=e;
}
void build_tree(int last,int x,int depth)
{
	int i;
	tree[x].lca[0]=tree[x].fat=last;
	tree[x].size=1;
	tree[x].wson=0;
	tree[x].dep=depth;
	for (i=1;i<=17;++i)
	  {
	    if (tree[x].dep >= 1<<i)
	      tree[x].lca[i]=tree[tree[x].lca[i-1]].lca[i-1];
	  }
	for (i=point[x];i;i=next[i])
	  if (a[i].v!=last)
	    {
	      build_tree(x,a[i].v,depth+1);
	      if (tree[tree[x].wson].size<tree[a[i].v].size)
	        tree[x].wson=a[i].v;
	    }
}
void build_seg(int now,int tp)
{
	int i;
	tree[now].top=tp;
	tree[now].ls=plc[now]=++totw;
	if (tree[now].wson!=0)
	  build_seg(tree[now].wson,tp);
	for (i=point[now];i;i=next[i])
	  if (a[i].v!=tree[now].fat&&a[i].v!=tree[now].wson)
	    build_seg(a[i].v,a[i].v);
	tree[now].rs=totw;
}
void updata(int i)
{
	seg[i].minn=min(seg[i<<1].minn,seg[i<<1|1].minn);
}
void paint(int i,int a)
{
	seg[i].minn=a;
	seg[i].delta=a;
}
void pushdown(int i)
{
	paint(i<<1,seg[i].delta);
	paint(i<<1|1,seg[i].delta);
	seg[i].delta=0;
}
void build(int i,int l,int r)
{
	if (l==r)
	  {
	    seg[i].minn=val[l];
	    return;
	  }
	build(lch); build(rch);
	updata(i);
}
void insert_seg(int i,int l,int r,int x,int y,int a)
{
	if (x<=l&&y>=r)
	  {
	    paint(i,a);
	    return;
	  }
	if (seg[i].delta!=0)
	  pushdown(i);
	if (x<=mid) insert_seg(lch,x,y,a);
	if (y>mid) insert_seg(rch,x,y,a);
	updata(i);
} 
void insert(int x,int y,int a)
{
	int f1=tree[x].top,f2=tree[y].top;
	while (f1!=f2)
	  {
	    if (tree[f1].dep<tree[f2].dep) {swap(f1,f2); swap(x,y);}
	    insert_seg(1,1,n,plc[f1],plc[x],a);
		x=tree[f1].fat; f1=tree[x].top; 
	  }
	if (tree[x].dep>tree[y].dep) swap(x,y);
	insert_seg(1,1,n,plc[x],plc[y],a);
}
int bz(int x,int depth)
{
	int i,v=x;
	for (i=0;i<=17;++i)
	  {
	    if (depth&(1<<i))
	      v=tree[v].lca[i];
	  }
	return v;
}
void query_seg(int i,int l,int r,int x,int y)
{
	if (x<=l&&y>=r)
	  {
	    ans=min(ans,seg[i].minn);
	    return;
	  }
	if (seg[i].delta!=0)
	  pushdown(i);
	if (x<=mid) query_seg(lch,x,y);
	if (y>mid) query_seg(rch,x,y);
} 
int LCA(int x,int y)
{
	int i,t;
	if (tree[x].dep<tree[y].dep) swap(x,y);
	t=tree[x].dep-tree[y].dep;
	for (i=0;i<=17;++i)
	  {
	    if (t&(1<<i))
	      x=tree[x].lca[i];
	  }
	for (i=17;i>=0;--i)
	  if (tree[x].lca[i]!=tree[y].lca[i])
	    {x=tree[x].lca[i]; y=tree[y].lca[i];}
	if (x==y) return x;
	else return tree[x].fat;
}
void work(int x)
{
	int lca,v,rootx=root,xx=x;
	lca=LCA(root,x);
	if (rootx==xx)//情况1
	  printf("%d\n",seg[1].minn);
	else
	  {
	    if (lca!=xx)//情况2
	      query_seg(1,1,n,tree[xx].ls,tree[xx].rs);
	    else//情况三
	      {
	        v=bz(rootx,tree[rootx].dep-tree[xx].dep-1);
	        if (tree[v].ls>1)
	          query_seg(1,1,n,1,tree[v].ls-1);
	        if (tree[v].rs<n)
		      query_seg(1,1,n,tree[v].rs+1,n);  
	      }
	    printf("%d\n",ans);
	  }
	root=rootx;
}
int main()
{
	int i,x,y,opt,a;
	scanf("%d%d",&n,&m);
	for (i=1;i<=n-1;++i)
	  {
	    scanf("%d%d",&x,&y);
	    add(x,y);
	  }
	build_tree(0,1,0);
	build_seg(1,1);
	for (i=1;i<=n;++i)
	  scanf("%d",&val[plc[i]]);
	build(1,1,n);
	scanf("%d",&root);
	for (i=1;i<=m;++i)
	  {
	    scanf("%d",&opt);
	    if (opt==1)
	      {
	        scanf("%d",&x);
	        root=x;
	      }
	    if (opt==2)
	      {
	        scanf("%d%d%d",&x,&y,&a);
			insert(x,y,a); 
	      }
	    if (opt==3)
	      {
	        scanf("%d",&x);
	        ans=inf;
	        work(x);
	      }
	  }
}

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页