zoukankan      html  css  js  c++  java
  • P4180 [BJWC2010]严格次小生成树

    P4180 [BJWC2010]严格次小生成树

    P4180

    题意

    求出一个无向联通图的严格次小生成树。严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次小生成树之间(不相等)。

    思路

    先求出一颗最小生成树,发现严格次小生成树一定是其断了一条边并加了一条边且边权和的增加量最小。

    那么我们继续在最小生成树上做。对于每一条不是最小生成树上的边,求出其两端两点间在最小生成树上路径上的边的最大值。然鹅,如果用倍增LCA找,发现如果求出来的最大值与该边权值相等,那么得出的答案就是不合法的。所以我们还必须维护一个倍增范围内严格次小边权

    然后找到最小的值输出就行啦!

    对于维护严格次小的值,我认为可以先求出最大值,然后比较找出与最大值不等的最大值就是次大值。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cctype>
    #define int long long
    using namespace std;
    inline int read(){
    	int w=0,x=0;char c=getchar();
    	while(!isdigit(c))w|=c=='-',c=getchar();
    	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return w?-x:x;
    }
    namespace star
    {
    	const int maxn=1e5+10,maxm=3e5+10,INF=0x3f3f3f3f3f3f3f3f;
    	int n,m;
    	struct Edge{
    		int u,v,dis;
    		bool is;
    		inline bool operator <(const Edge &zp)const {return dis<zp.dis;}
    	}e[maxm];
    	int ecnt,head[maxn],to[maxn<<1],Fa[maxn],nxt[maxn<<1],v[maxn<<1],ans=INF,sum,fa[maxn][25],mx[maxn][25],pmx[maxn][25],dep[maxn];
    	inline int find(int x){return Fa[x]==x?x:Fa[x]=find(Fa[x]);}
    	inline void addedge(int a,int b,int c){
    		to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt,v[ecnt]=c;
    		to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt,v[ecnt]=c;
    	}
    	inline void kruskal(){
    		for(int i=1;i<=n;i++)Fa[i]=i;
    		sort(e+1,e+1+m);
    		int cnt=0;
    		for(int i=1;i<=m;i++){
    			int fx=find(e[i].u),fy=find(e[i].v);
    			if(fx!=fy){
    				Fa[fx]=fy;
    				addedge(e[i].u,e[i].v,e[i].dis);
    				e[i].is=1;
    				sum+=e[i].dis;
    				if(++cnt==n-1)break;
    			}
    		}
    	}
    	void dfs(int x,int f){
    		fa[x][0]=f;
    		dep[x]=dep[f]+1;
    		for(int i=0;i<=20;i++){
    			fa[x][i+1]=fa[fa[x][i]][i];
    			mx[x][i+1]=max(mx[x][i],mx[fa[x][i]][i]);
    			if(mx[x][i+1]!=mx[x][i])pmx[x][i+1]=max(pmx[x][i+1],mx[x][i]);
    			if(mx[x][i+1]!=mx[fa[x][i]][i])pmx[x][i+1]=max(pmx[x][i+1],mx[fa[x][i]][i]);
    			if(mx[x][i+1]!=pmx[x][i])pmx[x][i+1]=max(pmx[x][i+1],pmx[x][i]);
    			if(mx[x][i+1]!=pmx[fa[x][i]][i])pmx[x][i+1]=max(pmx[x][i+1],pmx[fa[x][i]][i]);
    		}
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(u==f)continue;
    			mx[u][0]=v[i];
    			dfs(u,x);
    		}
    	}
    	inline void LCA(int x,int y,int &mxx,const int &MX){
    		if(dep[x]<dep[y])swap(x,y);
    		for(int i=20;i+1;i--)if(dep[fa[x][i]]>=dep[y]){
    			if(mx[x][i]!=MX)mxx=max(mxx,mx[x][i]);
    			else mxx=max(mxx,pmx[x][i]);
    			x=fa[x][i];
    		}
    		if(x==y)return;
    		for(int i=20;i+1;i--)if(fa[x][i]!=fa[y][i]){
    			if(mx[x][i]!=MX)mxx=max(mxx,mx[x][i]);
    			else mxx=max(mxx,pmx[x][i]);
    			x=fa[x][i];
    			if(mx[y][i]!=MX)mxx=max(mxx,mx[y][i]);
    			else mxx=max(mxx,pmx[y][i]);
    			y=fa[y][i];
    		}
    		if(mx[x][0]!=MX)mxx=max(mxx,mx[x][0]);
    			else mxx=max(mxx,pmx[x][0]);
    		if(mx[y][0]!=MX)mxx=max(mxx,mx[y][0]);
    			else mxx=max(mxx,pmx[y][0]);
    	}
    	inline void work(){
    		n=read(),m=read();
    		for(int i=1;i<=m;i++)e[i].u=read(),e[i].v=read(),e[i].dis=read();
    		kruskal();
    		dfs(1,0);
    		for(int i=1;i<=m;i++)if(!e[i].is){
    			int x=e[i].u,y=e[i].v,MX=-INF;
    			LCA(x,y,MX,e[i].dis);
    			ans=min(ans,sum-MX+e[i].dis);
    		}
    		printf("%lld",ans);
    	}
    }
    signed main(){
    	star::work();
    	return 0;
    }
    
  • 相关阅读:
    数组和字符串长度length
    Eclipse最有用快捷键整理
    Eclipse编辑java文件报Unhandled event loop exception错误的解决办法
    Java 删除项目中的.svn信息
    oracle 删除外键约束 禁用约束 启用约束
    Java Sftp上传下载文件
    java 如何判断操作系统是Linux还是Windows
    Javascript-正则表达式-开发中的使用.
    Eclipse和PyDev搭建完美Python开发环境 Windows篇
    ExtJS4为form表单必填项添加红色*标识
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/13732065.html
Copyright © 2011-2022 走看看