zoukankan      html  css  js  c++  java
  • 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
    ",Seg.query(1,1,n,1,n));
    	else if (!in(x,root)) printf("%d
    ",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
    ",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;
    }


  • 相关阅读:
    AC自动机学习笔记(模板)
    codeforces1328E
    Codeforces 1288E- Messenger Simulator (树状数组)
    线性基小记
    HDU3949
    矩阵快速幂小记
    5E
    5D
    5C
    5B
  • 原文地址:https://www.cnblogs.com/thythy/p/5493596.html
Copyright © 2011-2022 走看看