题目描述

小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)∑e∈EM​​value(e)<∑e∈ES​​value(e)

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
输出样例#1: 复制

11

说明

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

裸的次小生成树

具体怎么实现一会儿整理一下挂个链接吧

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#define int long long
using namespace std;
const int MAXN=;
const int INF=1e15+;
inline int read()
{
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
struct Edge
{
int u,v,w;
}E[MAXN];
int Enum=;
void Add(int x,int y,int z)
{
E[Enum].u=x;
E[Enum].v=y;
E[Enum].w=z;Enum++;
}
struct node
{
int u,v,w,nxt;
}edge[MAXN];
int head[MAXN];
int num=;
int N,M;
int fa[MAXN],vis[MAXN],sum;
int deep[MAXN],f[MAXN][],maxx[MAXN][],minx[MAXN][];
void AddEdge(int x,int y,int z)
{
edge[num].u=x;
edge[num].v=y;
edge[num].w=z;
edge[num].nxt=head[x];
head[x]=num++;
}
int find(int x)
{
if(fa[x]==x) return fa[x];
else return fa[x]=find(fa[x]);
}
int unionn(int x,int y)
{
int fx=find(x),fy=find(y);
fa[fx]=fy;
}
int comp(const Edge &a,const Edge &b)
{
return a.w<b.w;
}
void Kruskal()
{
sort(E+,E+Enum,comp);
int tot=;
for(int i=;i<=Enum-;i++)
{
int x=E[i].u,y=E[i].v;
if(find(x)!=find(y))
{
unionn(x,y),tot++,sum+=E[i].w,vis[i]=;
AddEdge(x,y,E[i].w);AddEdge(y,x,E[i].w);
}
if(tot==N-) break;
}
}
void dfs(int now,int fa)
{
for(int i=head[now];i!=-;i=edge[i].nxt)
{
if(edge[i].v==fa) continue;
deep[edge[i].v]=deep[edge[i].u]+;
f[edge[i].v][]=now;
maxx[edge[i].v][]=edge[i].w;
dfs(edge[i].v,now);
}
}
void pre()
{
for(int i=;i<=;i++)
{
for(int j=;j<=N;j++)
{
f[j][i]=f[ f[j][i-] ][i-];
maxx[j][i]=max(maxx[j][i-],maxx[ f[j][i-] ][i-]);
minx[j][i]=max(minx[j][i-],minx[ f[j][i-] ][i-]);
if(maxx[j][i-]>maxx[ f[j][i-] ][i-]) minx[j][i]=max(minx[j][i],maxx[ f[j][i-] ][i-]);
else minx[j][i]=max(minx[j][i],maxx[j][i-]);
}
}
}
int LCA(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for(int i=;i>=;i--)
if(deep[ f[x][i] ] >= deep[y] )
x=f[x][i];
if(x==y) return x;
for(int i=;i>=;i--)
if(f[x][i] != f[y][i])
x=f[x][i],y=f[y][i];
return f[x][];
}
int findmax(int x,int lca,int val)
{
int ans=;
for(int i=;i>=;i--)
{
if(deep[ f[x][i] ] >= deep[lca])
{
if(maxx[x][i]==val) ans=max(ans,minx[x][i]);
else ans=max(ans,maxx[x][i]);
x=f[x][i];
}
}
return ans;
}
void work()
{
int ans=INF;
for(int i=;i<=Enum-;i++)
{
if(vis[i]) continue;
int x=E[i].u,y=E[i].v,z=E[i].w;
int lca=LCA(x,y);
int lmx=findmax(x,lca,z);
int rmx=findmax(y,lca,z);
if(max(lmx,rmx)!=z)
ans=min(ans,sum+z-max(lmx,rmx));
}
printf("%lld",ans);
}
main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
N=read(),M=read();
memset(head,-,sizeof(head));
for(int i=;i<=N;i++) fa[i]=i;
for(int i=;i<=M;i++)
{
int x=read(),y=read(),z=read();
Add(x,y,z);
}
Kruskal();
deep[]=;
dfs(,);
pre();
work();
return ;
}

洛谷P4180 [Beijing2010组队]次小生成树Tree的更多相关文章

  1. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  2. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  3. 1977: [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...

  4. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  5. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

  6. 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)

    洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...

  7. 【洛谷P4180】严格次小生成树

    题目大意:给定一个 N 个顶点,M 条边的带权无向图,求该无向图的一个严格次小生成树. 引理:有至少一个严格次小生成树,和最小生成树之间只有一条边的差异. 题解: 通过引理可以想到一个暴力,即:先求出 ...

  8. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  9. (luogu4180) [Beijing2010组队]次小生成树Tree

    严格次小生成树 首先看看如果不严格我们怎么办. 非严格次小生成树怎么做 由此,我们发现一个结论,求非严格次小生成树,只需要先用kruskal算法求得最小生成树,然后暴力枚举非树边,替换路径最大边即可. ...

随机推荐

  1. EditText电话号码格式化输入、删除案例

    我们在输入电话号码的时候,一般都会切割一个较长的电话号码.这种话效果会好非常多..对EditText的监听能够轻松的实现这个需求.仅仅须要我们给相应的EditText加一个监听就OK了..贴一下我写的 ...

  2. HDOJ find the safest road 1596【最短路变形】

    find the safest road Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  3. Binary Tree Inorder Traversal--leetcode

    原题链接:https://oj.leetcode.com/problems/binary-tree-inorder-traversal/ 题目大意:中序遍历二叉树 解题思路:中序遍历二叉树.中序遍历二 ...

  4. 关于iOS7中UIView效果失效问题的解决

    最近想做一个跑马灯的效果.于是写出了例如以下的跑马灯效果的代码...可是调试发现,在iOS6下动画是能够运行的,可是在iOS7下动画并不运行,没有达到预期的效果. [_scrollLabel size ...

  5. iOS7实现带文本输入框的UIAlertView及获取TextField文本内容

    if (customAlertView==nil) { customAlertView = [[UIAlertView alloc] initWithTitle:@"自定义服务器地址&quo ...

  6. 接口、索引器、Foreach的本质(学习笔记)

    接口 什么是接口? 接口代表一种能力,和抽象类类似但比抽象类的抽象程度更高! 接口的定义: public interface IEat//定义一个接口 { void Eat(string food); ...

  7. 手把手教你如何新建scrapy爬虫框架的第一个项目(上)

    前几天给大家分享了如何在Windows下创建网络爬虫虚拟环境及如何安装Scrapy,还有Scrapy安装过程中常见的问题总结及其对应的解决方法,感兴趣的小伙伴可以戳链接进去查看.关于Scrapy的介绍 ...

  8. 洛谷P3355 骑士共存问题 二分图_网络流

    Code: #include<cstdio> #include<cstring> #include<queue> #include<vector> #i ...

  9. NOIp2018模拟赛三十八

    爆〇啦~ A题C题不会写,B题头铁写正解: 随手过拍很自信,出分一看挂成零. 若要问我为什么?gtmdsubtask! 神tm就一个subtask要么0分要么100,结果我预处理少了一点当场去世 难受 ...

  10. BZOJ 5254 [Fjwc2018]红绿灯 (线段树)

    题目大意:一个wly从家走到学校要经过n个红绿灯,绿灯持续时间是$g$,红灯是$r$,所有红绿灯同时变红变绿,交通规则和现实中一样,不能抢红灯,两个红绿灯之间道路的长度是$di$,一共$Q$个询问,求 ...