zoukankan      html  css  js  c++  java
  • P4234 最小差值生成树

    https://www.luogu.com.cn/problem/P4234

    求最小差值生成树

    考虑先把边从小到大排序(从大到小也可以,就是反过来而已)
    然后一条条边枚举,如果两端点还未联通,直接联通
    如果整个图已经联通了,此时可以理解为枚举了边的最大值(因为边权从小到大排序了),最大值确定,就应该要让最小值越大越好,又因为要在这两个端点行成的路径上删掉一个点,那么就删掉环上权值最小的点
    所以按照上面的描述每次如果每联通就联通,如果联通了就删路径权值最小边并加新边就行了,用 lct 维护,因为涉及边的信息,还要用新建虚拟节点表示边

    然后每次枚举时,如果整个图联通,就用当前边权减去当前全局最小值,全局最小值用带删除的堆维护的,好像有点麻烦了

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 50005
    #define M 200005
    int n,m;
    int U[M],V[M],w[M];
    int tmp[10];
    struct tr{
    	tr *son[2],*fa;
    	int tag;
    	int valmin,min;
    	int valmax,max;
    }*null,*pos[N+M],dizhi[N+M];
    #define ident(tree,fa) (fa->son[1]==tree)
    #define notroot(tree) (tree->fa->son[0]==tree||tree->fa->son[1]==tree)
    inline void connect(tr *tree,tr *fa,int k){fa->son[k]=tree;tree->fa=fa;}
    inline void pushdown(tr *tree){
    	if(!tree->tag) return;
    	tree->son[0]->tag^=1;tree->son[1]->tag^=1;
    	std::swap(tree->son[0],tree->son[1]);
    	tree->tag=0;
    }
    inline int min(int x,int y){return w[x]<w[y]?x:y;}
    inline int max(int x,int y){return w[x]>w[y]?x:y;}
    inline void pushup(tr *tree){
    	tree->min=min(tree->valmin,min(tree->son[0]->min,tree->son[1]->min));
    	tree->max=max(tree->valmax,max(tree->son[0]->max,tree->son[1]->max));
    }
    inline void rotate(tr *tree){
    	tr *fa=tree->fa,*faa=fa->fa;
    	pushdown(fa);pushdown(tree);
    	int k=ident(tree,fa);
    	connect(tree->son[k^1],fa,k);
    	tree->fa=faa;
    	if(notroot(fa)) faa->son[ident(fa,faa)]=tree;
    	connect(fa,tree,k^1);
    	pushup(fa);pushup(tree);
    }
    inline void splay(reg tr *tree){
    	reg tr *fa,*faa;
    	while(notroot(tree)){
    		fa=tree->fa;faa=fa->fa;
    		if(notroot(fa)) rotate(ident(tree,fa)^ident(fa,faa)?tree:fa);
    		rotate(tree);
    	}
    }
    inline void access(reg tr *x){
    	for(reg tr *lastx=null;x!=null;lastx=x,x=x->fa){
    		pushdown(x);
    		splay(x);
    		x->son[1]=lastx;pushup(x);
    	}
    }
    inline void makeroot(tr *x){
    	access(x);
    	splay(x);
    	x->tag^=1;
    }
    inline tr *findroot(tr *x){
    	access(x);splay(x);
    	pushdown(x);
    	while(x->son[0]!=null) x=x->son[0],pushdown(x);
    	splay(x);
    	return x;
    }
    inline int linked(tr *x,tr *y){
    	makeroot(x);
    	return findroot(y)==x;
    }
    inline void split(tr *x,tr *y){
    	makeroot(x);
    	access(y);splay(y);
    }
    inline void link(tr *x,tr *y){
        makeroot(x);
    	if(findroot(y)!=x) x->fa=y;
    }
    inline void cut(tr *x,tr *y){
        split(x,y);
        x->fa=y->son[0]=null;
    }
    inline void init(){
    	null=&dizhi[0];
    	dizhi[0].max=dizhi[0].valmax=m+1;
    	for(reg int i=1;i<=n;i++){
    		pos[i]=&dizhi[i];
    		dizhi[i].son[0]=dizhi[i].son[1]=dizhi[i].fa=null;
    		dizhi[i].max=dizhi[i].valmax=m+1;
    	}
    	w[0]=1e9;w[m+1]=-1e9;
    }
    inline void creat(int i){
    	pos[i]=&dizhi[i];
    	dizhi[i].son[0]=dizhi[i].son[1]=dizhi[i].fa=null;
    	dizhi[i].min=dizhi[i].valmin=i-n;
    	dizhi[i].max=dizhi[i].valmax=i-n;
    }
    struct edges{
    	int u,v,w;
    }edge[M];
    inline int cmp_edge(edges a,edges b){return a.w<b.w;}
    struct HEAP{
    	std::priority_queue<int>ins,del;
    	inline void delete_(int num){del.push(num);}
    	inline void insert(int num){ins.push(num);}
    	inline int top(){
    		while(!del.empty()&&!ins.empty()&&del.top()==ins.top()) del.pop(),ins.pop();
    		return ins.top();
    	}
    }heap;
    int main(){
    	n=read();m=read();
    	init();
    	for(reg int i=1;i<=m;i++) edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
    	std::sort(edge+1,edge+1+m,cmp_edge);
    	int u,v,ans=1e9;
    	for(reg int i=1,cnt=1;i<=m;i++){
    		u=U[i]=edge[i].u;v=V[i]=edge[i].v;w[i]=edge[i].w;
    		creat(i+n);
    		if(u==v) continue;
    		if(!linked(pos[u],pos[v])){
    			link(pos[u],pos[i+n]),link(pos[v],pos[i+n]);cnt++;
    			heap.insert(-w[i]);
    		}
    		else{
    			split(pos[u],pos[v]);
    			int tmp=pos[v]->min;
    			cut(pos[U[tmp]],pos[tmp+n]);cut(pos[V[tmp]],pos[tmp+n]);
    			link(pos[u],pos[i+n]);link(pos[v],pos[i+n]);
    			heap.delete_(-w[tmp]);heap.insert(-w[i]);
    		}
    		if(cnt==n) ans=std::min(ans,w[i]+heap.top());
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    python学习--大数据与科学计算第三方库简介
    养生轴---茶轴
    MobaXterm的安装和使用
    如何解决RIP的问题
    评论博客时注意的地方
    回忆老师教学博客
    助教自我介绍
    《构建之法》读书笔记1
    插入排序
    总结之H3C汇聚层交换机认证在线人数展示系统
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13502214.html
Copyright © 2011-2022 走看看