• [BZOJ1977/BeiJing2010组队]次小生成树 Tree


    Description
    小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    Input
    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

    Output
    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    Sample Input
    5 6
    1 2 1
    1 3 2
    2 4 3
    3 5 4
    3 4 3
    4 5 6

    Sample Output
    11

    HINT
    数据中无向图无自环;
    50% 的数据N≤2 000 M≤3 000;
    80% 的数据N≤50 000 M≤100 000;
    100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。


    首先建出最小生成树,然后对于非树边(u,v),它能产生贡献,当且仅当u,v在树上路径上有条边被切断了。于是我们用树剖找出路径上最长的边,将其用(u,v)替换,即可得到次小生成树了。但我们需要得到严格次小生成树,那么就会出现路径上最长的边和w(u,v)相同的情况,这是我们就需要找到一条次小边,那么线段树维护两个值即可。

    记得判掉重边的影响。。。

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5,M=3e5;
    int v[N+10],dfn[N+10],ID[N+10];
    int n,m;
    struct S1{
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	struct node{
    		int f,g;
    		node(){f=g=-inf;}
    		void insert(int _f,int _g){f=_f,g=_g;}
    	}tree[(N<<2)+10];
    	friend node operator +(const node &x,const node &y){
    		node z;
    		z.f=max(x.f,y.f);
    		z.g=max(x.g,y.g);
    		if (x.f!=y.f)	z.g=max(z.g,min(x.f,y.f));
    		return z;
    	}
    	void build(int p,int l,int r){
    		if (l==r){
    			tree[p].insert(v[dfn[l]],-inf);
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(ls,l,mid),build(rs,mid+1,r);
    		tree[p]=tree[ls]+tree[rs];
    	}
    	node Query(int p,int l,int r,int x,int y){
    		if (x<=l&&r<=y)	return tree[p];
    		int mid=(l+r)>>1; node res;
    		if (x<=mid)	res=res+Query(ls,l,mid,x,y);
    		if (y>mid)	res=res+Query(rs,mid+1,r,x,y);
    		return res;
    	}
    }ST;//Segment Tree
    struct S2{
    	int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10];
    	int top[N+10],Rem[N+10],deep[N+10],size[N+10],fa[N+10];
    	int tot,Time;
    	void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    	void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    	void build(int x){
    		deep[x]=deep[fa[x]]+1,size[x]=1;
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x])	continue;
    			fa[son]=x,v[son]=val[p];
    			build(son),size[x]+=size[son];
    			if (size[Rem[x]]<size[son])	Rem[x]=son;
    		}
    	}
    	void dfs(int x){
    		if (!x)	return;
    		dfn[ID[x]=++Time]=x;
    		top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
    		dfs(Rem[x]);
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x]||son==Rem[x])	continue;
    			dfs(son);
    		}
    	}
    	int Get(int x,int y,int z){
    		S1::node res;
    		while (top[x]!=top[y]){
    			if (deep[top[x]]<deep[top[y]])	swap(x,y);
    			res=res+ST.Query(1,1,n,ID[top[x]],ID[x]);//+被重载了,在ST结构体里面
    			x=fa[top[x]];
    		}
    		if (x!=y){
    			if (deep[x]>deep[y])	swap(x,y);
    			res=res+ST.Query(1,1,n,ID[Rem[x]],ID[y]);
    		}
    		if (res.f==-inf&&res.g==-inf)	return inf;//开始没判,后面因为重边导致res两个信息都为-inf,于是炸int了。。。
    		return z-(z==res.f?res.g:res.f);
    	}
    }HLD;//Heavy-Light Decomposition
    struct S3{
    	int fa[N+10];
    	void init(){for (int i=1;i<=n;i++)	fa[i]=i;}
    	int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    }DSU;//Disjoint Set Union
    struct S4{
    	int x,y,z,type;
    	S4(){type=0;}
    	void insert(){x=read(),y=read(),z=read();}
    	bool operator <(const S4 &a)const{return z<a.z;}
    }A[M+10];
    int main(){
    	n=read(),m=read();
    	for (int i=1;i<=m;i++)	A[i].insert();
    	sort(A+1,A+1+m);
    	DSU.init();
    	ll MST=0;int Ans=inf;
    	for (int i=1;i<=m;i++){
    		int x=DSU.find(A[i].x),y=DSU.find(A[i].y);
    		if (x!=y)	DSU.fa[x]=y,HLD.insert(A[i].x,A[i].y,A[i].z),A[i].type=1,MST+=A[i].z;
    	}
    	HLD.build(1),HLD.dfs(1),ST.build(1,1,n);
    	for (int i=1;i<=m;i++){
    		if (A[i].type)	continue;
    		Ans=min(Ans,HLD.Get(A[i].x,A[i].y,A[i].z));
    	}
    	printf("%lld
    ",MST+Ans);
    	return 0;
    }
    
  • 相关阅读:
    Jenkins与Hudson的关系
    Jenkins企业版与CloudBees
    NSLookup命令
    XCopy提示“访问遭到拒绝”问题解决
    npm配置文件
    npm下载包时代理配置
    Jenkins实现测试环境到生产环境一键部署(Windows)
    可能是迄今为止最好的GitHub代码浏览插件--赞
    Ali OSS服务端签名直传并设置上传回调
    导入https证书
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9746698.html
Copyright © 2020-2023  润新知