bzoj3083: 遥远的国度

题意:给定一棵树,支持换根,路径权值覆盖,求子树最小。

思路:求子树?上树链剖分,但是换根怎么办?我们只能通过原有信息推出换根后的答案。换根不影响路径修改,所以只要考虑子树最小值的维护。

这里要分3种情况讨论

1:如果询问点是当前根,直接返回整棵树的最小值。

2:如果在原树中,当前根不在x的子树中,直接返回原树中x的子树最小值。判断x在不在y的子树中,只要通过dfs序即可,如果x的dfs序大于y,且小于等于y子树中最后一个点的dfs序,那么x就在y的子树中。

3:如果在原树中,当前根x的子树中,那么就相当于去掉当前根所在的x的儿子的子树的整棵树(语文没学好..具体见图..)

然后这题就解决了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((l+r)>>1)
const int maxn=100010,maxm=200010,maxt=maxn<<3;
using namespace std;
int n,m,pre[maxm],now[maxn],son[maxm],col[maxn],tot,root;
int fa[maxn],hson[maxn],w[maxn],top[maxn],dep[maxn],size[maxn],T,q,z[maxn],cnt,def[maxn],a[maxn],op,last[maxn];
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}

struct tree{
	static const int inf=2147483647;
	int mins[maxt],cov[maxt];
	void update(int p){mins[p]=min(mins[ls],mins[rs]);}
	void down(int p){if (cov[p]) mins[ls]=mins[rs]=cov[ls]=cov[rs]=cov[p],cov[p]=0;}
	void build(int p,int l,int r){
		if (l==r){mins[p]=a[l];return;}
		build(ls,l,mid),build(rs,mid+1,r);
		update(p);
	}
	void change(int p,int l,int r,int a,int b,int v){
		if (l==a&&r==b){cov[p]=mins[p]=v;return;}
		down(p);
		if (b<=mid) change(ls,l,mid,a,b,v);
		else if (a>mid) change(rs,mid+1,r,a,b,v);
		else change(ls,l,mid,a,mid,v),change(rs,mid+1,r,mid+1,b,v);
		update(p);
	}
	int query(int p,int l,int r,int a,int b){
		if (a>b) return inf;
		if (l==a&&r==b){return mins[p];}
		down(p);
		if (b<=mid) return query(ls,l,mid,a,b);
		else if (a>mid) return query(rs,mid+1,r,a,b);
		else return min(query(ls,l,mid,a,mid),query(rs,mid+1,r,mid+1,b));
	}
}Seg;

void dfs(int x){
	size[x]=1;
	for (int y=now[x];y;y=pre[y])
		if (son[y]!=fa[x]){
			fa[son[y]]=x,dep[son[y]]=dep[x]+1,dfs(son[y]);
			size[x]+=size[son[y]];
			if (size[son[y]]>size[hson[x]]) hson[x]=son[y];
		}
}

void btree(int x,int tp){
	w[x]=++m,a[m]=def[x],top[x]=tp;
	if (hson[x]) btree(hson[x],top[x]);
	for (int y=now[x];y;y=pre[y])
		if (son[y]!=fa[x]&&hson[x]!=son[y])
			btree(son[y],son[y]);
	last[x]=m;
}
bool in(int root,int a){return w[a]>=w[root]&&w[a]<=last[root];}
void cover(int a,int b,int v){
	int f1=top[a],f2=top[b];
	while (f1!=f2){
		if (dep[f1]<dep[f2]) swap(f1,f2),swap(a,b);
		Seg.change(1,1,m,w[f1],w[a],v);
		a=fa[f1],f1=top[a];
	}
	if (dep[a]>dep[b]) swap(a,b);
	Seg.change(1,1,m,w[a],w[b],v);
}

void answer(int x){
	if (x==root) printf("%d\n",Seg.query(1,1,n,1,n));
	else if (!in(x,root)) printf("%d\n",Seg.query(1,1,n,w[x],last[x]));
	else for (int y=now[x];y;y=pre[y])
			if (in(son[y],root)&&son[y]!=fa[x]){
				printf("%d\n",min(Seg.query(1,1,n,1,w[son[y]]-1),Seg.query(1,1,n,last[son[y]]+1,n)));
				break;
			}
}

int main(){
//	freopen("country.in","r",stdin);freopen("country.out","w",stdout);
	scanf("%d%d",&n,&q);
	for (int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),add(a,b),add(b,a);
	for (int i=1;i<=n;i++) scanf("%d",&def[i]);
	scanf("%d",&root);
	dfs(root),btree(root,root);Seg.build(1,1,m);
	for (int i=1,a,b,c;i<=q;i++){
		scanf("%d",&op);
		if (op==1) scanf("%d",&a),root=a;
		else if (op==2) scanf("%d%d%d",&a,&b,&c),cover(a,b,c);
		else scanf("%d",&a),answer(a);
	}
//	fclose(stdout);
	return 0;
}


posted @ 2015-06-22 21:11  orzpps  阅读(136)  评论(0编辑  收藏  举报