[BZOJ1977]严格次小生成树
【问题描述】
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。
正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)
这下小C蒙了,他找到了你,希望你帮他解决这个问题。
【输入格式】
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点x和点y之间有一条边,边的权值为z。
【输出格式】
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
【输入样例】
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
【输出样例】
11
【数据范围】
数据中无向图无自环;
50% 的数据N≤2 000 M≤3 000;
80% 的数据N≤50 000 M≤100 000;
100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解:
要求求严格次小生成树,首先kruskal就无法使用,prim复杂度太高
于是我们用LCA
构造出最小生成树,可知次小生成树肯定是加入某边再删去一边
假设加入(i,j)则有删去生成树上i~j路径最大的边,用倍增维护
但是严格次小没有解决
可以在用倍增维护最大值时,再维护次小值,那么当最大值等于加入边权值时则删去次大边
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lol;
struct Messi
{
lol u,v;
lol dis;
}edge1[];
struct Node
{
lol next,to;
lol dis;
}edge[];
lol num,head[],set[],depth[],Max[][],Max2[][],fa[][],n,m,ans1,ans=2e9;
bool vis[],b[];
bool cmp(Messi a,Messi b)
{
return a.dis<b.dis;
}
void add(lol u,lol v,lol dis)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
edge[num].dis=dis;
}
lol find(lol x)
{
if (set[x]!=x) set[x]=find(set[x]);
return set[x];
}
void dfs(lol x,lol dep)
{int i;
vis[x]=;
depth[x]=dep;
for (i=;i<=;i++)
if (dep>(<<i))
{
Max[x][i]=max(Max[x][i-],Max[fa[x][i-]][i-]);
if (Max[x][i-]!=Max[fa[x][i-]][i-]) Max2[x][i]=Max[x][i-]+Max[fa[x][i-]][i-]-Max[x][i];
Max2[x][i]=max(Max2[x][i],max(Max2[x][i-],Max2[fa[x][i-]][i-]));
fa[x][i]=fa[fa[x][i-]][i-];
}
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (vis[v]==)
{
fa[v][]=x;
Max[v][]=edge[i].dis;
dfs(v,dep+);
}
}
}
lol ask(lol x,lol y,lol d)
{int i;
lol s1=,s2=;
if (depth[x]<depth[y]) swap(x,y);
for (i=;i>=;i--)
if ((<<i)<=depth[x]-depth[y])
{
if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
s2=max(s2,Max2[x][i]);
s1=max(s1,Max[x][i]);
x=fa[x][i];
}
if (x==y)
{
if (s1==d&&s2) return d-s2;
else if (s2==) return 2e9;
else if (s1!=d)return d-s1;
}
for (i=;i>=;i--)
{
if ((<<i)<depth[x]&&fa[x][i]!=fa[y][i])
{
if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
s2=max(s2,Max2[x][i]);
s1=max(s1,Max[x][i]);
if (s1!=Max[y][i]) s2=max(s2,min(s1,Max[y][i]));
s2=max(s2,Max2[y][i]);
s1=max(s1,Max[y][i]);
x=fa[x][i];y=fa[y][i];
}
}
if (s1!=Max[x][]) s2=max(s2,min(s1,Max[x][]));
s2=max(s2,Max2[x][]);
s1=max(s1,Max[x][]);
if (s1!=Max[y][]) s2=max(s2,min(s1,Max[y][]));
s2=max(s2,Max2[y][]);
s1=max(s1,Max[y][]);
x=fa[x][];y=fa[y][];
if (s1==d&&s2) return d-s2;
else if (s2==) return 2e9;
else if (s1!=d)return d-s1;
}
int main()
{int i,j,q,opt,x,y;
//freopen("scrip.in","r",stdin);
//freopen("scrip.out","w",stdout);
cin>>n>>m;
for (i=;i<=m;i++)
{
scanf("%d%d%d",&edge1[i].u,&edge1[i].v,&edge1[i].dis);
}
sort(edge1+,edge1+m+,cmp);
for (i=;i<=n;i++)
set[i]=i;
i=;j=;
while (i<=n-&&j<=m)
{
int p=find(edge1[j].u),q=find(edge1[j].v);
if (p!=q)
{
set[p]=q;
i++;
b[j]=;
ans1+=edge1[j].dis;
add(edge1[j].u,edge1[j].v,edge1[j].dis);
add(edge1[j].v,edge1[j].u,edge1[j].dis);
}
j++;
}
if (i<=n-)
{
cout<<"No MST!";
return ;
}
dfs(,);
for (j=;j<=m;j++)
{
if (b[j]==)
{
ans=min(ans,ask(edge1[j].u,edge1[j].v,edge1[j].dis));
}
}
if (ans==2e9)
{
cout<<"No SST!";
return ;
}
cout<<ans+ans1;
}
[BZOJ1977]严格次小生成树的更多相关文章
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...
- bzoj1977次小生成树(重要)
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...
- [BZOJ1977][BeiJing2010组队]次小生成树
题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
- bzoj1977 次小生成树
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
随机推荐
- 福州大学软工1715|W班-启航
新的一学期即将开启,而在仅剩的几天的时间内,我将为接下来的软工实践助教事宜忙碌起来.要学习的东西很多,要关注的东西也很多. 虽然我现在还在茫然阶段,虽然我对<构建之法>还不太熟悉,但是,我 ...
- Scrum 冲刺 第一日
Scrum 冲刺 第一日 站立式会议 燃尽图 Alpha 阶段认领任务 明日任务安排 项目预期任务量 成员贡献值计算规则 今日贡献量 参考资料 站立式会议 返回目录 燃尽图 返回目录 Alpha 阶段 ...
- js中多维数组转一维
法一:使用数组map()方法,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组. var arr = [1,[2,[[3,4],5],6]]; function unid(arr){ v ...
- python之路--day6---文件处理
一.文件 1.文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件, 可以将自己的数据永久保存下来. 2.操作流程 #1. 打开文件,得到文件句柄并赋值给一个变量--f = o ...
- java JDK源码解析
Hashmap 使用java语言进行系统开发时,使用得比较多得数据结构hashmap,它以[key,value],进行数据存储,通过key可以快速找到到对应的value值,但是key,value不能是 ...
- javascript原型链__proto__属性的理解
在javascript中,按照惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头.一个方法使用new操作符创建,例如下面代码块中的Person1(可以吧Person1看做 ...
- DNS搜索过程
以www.renyi.com为例 一:客户端首先检查本地HOST文件,是否有对应的IP地址,如果有,客户端直接访问,如果没有,则执行下一步. 二:客户端查看本地缓存信息,是否有对应的IP地址,如果有, ...
- Python机器学习—导入各种数据的N种办法
pandas 读取数据 一.导入一般的文件 1.read_csv(),用来读取CSV文件 官方文档是这么说的:Read CSV (comma-separated) file into DataFram ...
- javaScript识别网址文本并转为链接文本
最近项目有个需求:用户之间发送消息时,如果发送者输入的信息中含有网址文本,要在接受者界面中显示网址链接,点击该链接直接跳转到网页.这个功能和 QQ 发送网址文本的效果非常像,可以说是一模一样的. 思路 ...
- 《深入实践Spring Boot》阅读笔记之二:分布式应用开发
上篇文章总结了<深入实践Spring Boot>的第一部分,这篇文章介绍第二部分:分布式应用开发,以及怎么构建一个高性能的服务平台. 主要从以下几个方面总结: Spring Boot SS ...