您的位置:首页 > 其它

【bzoj3306】 树 dfs序+线段树

2015-08-17 13:23 316 查看
并不是太难,只要处理换根操作就好了,因为这棵树的形态是不变的。那么按照点1为根时的dfs序,若当前根在x点的子树外,则答案还是x的子树,若当前根是x,那么答案是整棵树,若当前的根在x的子树内,则答案就是抠掉根所在的那一枝后的答案(画个图就明白了)。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define inf 1000000000

using namespace std;

struct yts
{
	int data;
	int l,r;
}a[4*maxn];

int e[maxn],next[2*maxn],head[maxn],to[2*maxn],g[maxn],w[maxn],in[maxn],out[maxn];
int fa[maxn][20],dep[maxn];
int n,m,root,num,T,tot;

void addedge(int x,int y)
{
	num++;to[num]=y;next[num]=head[x];head[x]=num;
}

void dfs(int x)
{
	e[++tot]=x;in[x]=tot;
	for (int p=head[x];p;p=next[p])
	  if (to[p]!=g[x]) dep[to[p]]=dep[x]+1,dfs(to[p]);
	out[x]=tot;
}

void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	if (l==r) {a[i].data=w[e[l]];return;}
	int mid=(l+r)/2;
	build(i*2,l,mid);build(i*2+1,mid+1,r);
	a[i].data=min(a[i*2].data,a[i*2+1].data);
}

void modify(int i,int x,int d)
{
	if (a[i].l==a[i].r) {a[i].data=d;return;}
	int mid=(a[i].l+a[i].r)/2;
	if (x<=mid) modify(i*2,x,d);
	if (mid<x) modify(i*2+1,x,d);
	a[i].data=min(a[i*2].data,a[i*2+1].data);
}

int query(int i,int l,int r)
{
	if (l>r) return inf;
	if (l<=a[i].l && a[i].r<=r) return a[i].data;
	int mid=(a[i].l+a[i].r)/2,ans=inf;
	if (l<=mid) ans=min(ans,query(i*2,l,r));
	if (mid<r) ans=min(ans,query(i*2+1,l,r));
	return ans;
}

int go_up(int x,int d)
{
	for (int i=19;i>=0;i--)
	  if (d&(1<<i)) x=fa[x][i];
	return x;
}

int main()
{
	scanf("%d%d",&n,&T);
	for (int i=1;i<=4*n;i++) a[i].data=inf;
	for (int i=1;i<=n;i++)
	  scanf("%d%d",&g[i],&w[i]);
	for (int i=1;i<=n;i++)
	  if (g[i]) addedge(g[i],i);
	  else root=i;
	dep[1]=0;dfs(1);
	for (int i=1;i<=n;i++) fa[i][0]=g[i];
	for (int j=1;j<=19;j++)
	  for (int i=1;i<=n;i++)
	    if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];
	    else fa[i][j]=0;
	build(1,1,n);
	while (T--)
	{
		char op[5];
		int x,y;
		scanf("%s%d",op,&x);
		if (op[0]=='V')
		{
			scanf("%d",&y);
			modify(1,in[x],y);
		}
		if (op[0]=='E') root=x;
		if (op[0]=='Q')
		{
			if (root==x) printf("%d\n",query(1,1,n));
			else 
			if (in[x]<=in[root] && out[root]<=out[x]) 
			{
				int y=go_up(root,dep[root]-dep[x]-1);
				printf("%d\n",min(query(1,1,in[y]-1),query(1,out[y]+1,n)));
			}
			else printf("%d\n",query(1,in[x],out[x]));
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: