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;
    }


  • 相关阅读:
    打造基于CentOS7的xfce最简工作环境
    Linux下C程序的编辑,编译和运行以及调试
    修正 XE6 TListView 上方 SearchBok 右边的清除钮显示
    TabControl 显示彩色的图示 (XE6 Firemonkey)
    TSwitch 中文简繁显示支持(XE6 Android)
    改变 TMemo 的背景颜色 (Firemonkey)
    修正 XE5 Android 键盘三个问题
    Delphi 收藏
    展示 Popup 的使用方法
    ListView 下拉更新 (支持 Android)
  • 原文地址:https://www.cnblogs.com/thythy/p/5493596.html
Copyright © 2011-2022 走看看