[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的路径上的最大 ...
随机推荐
- C语言作业--函数
一.PTA实验作业 题目1: 400-499 中4出现的次数 1. 本题PTA提交列表 2. 设计思路 一.main函数 1.函数声明int fun(int x) 2.定义变量i,k,i表示输入的值, ...
- C语言数据类型作业
一.PTA实验作业 题目1:7-4 打印菱形图案 1. 本题PTA提交列表 2. 设计思路 1.定义m,n(用于计算空格数,输出"* "数),i,j,k(用于循环) 2.输入n,并 ...
- 敏捷冲刺报告--Day5
敏捷冲刺报告--Day5 情况简介 GUI框架重写, 添加功能 任务进度 赵坤: 后端爬虫bug修复 李世钰: GUI编写 黄亦薇:更新sprint backlog.编写每日报告 王成科:召集小组成员 ...
- 使用XIB实现嵌套自定义视图
在进行iOS开发的过程中,对于一些复杂的界面,我们可以通过Interface Builder这个Xcode集成的可视化界面编辑工具在完成,这回节省大部分时间以及代码量.它的使用方法这里不做介绍了,这次 ...
- HNOI 2012 永无乡
codevs 1477 永无乡 http://codevs.cn/problem/1477/ 2012年湖南湖北省队选拔赛 时间限制: 1 s 空间限制: 128000 KB 题目描述 Des ...
- windows 10下通过python3.6成功搭建jupyter 服务器
最近通过python学习爬虫技术,发现一个工具jupyter notebook很不错,该工具明显优势通过浏览器可以输入多行python代码,支持在线运行以及运行结果保存功能,在线验证python小模块 ...
- LR之error(一)
1 录制时频繁卡死的解决方案 添加数据保护 路径:计算机--高级系统设置(环境变量设置的上级窗口)--高级--设置--数据执行保护 更改LR录制设置,将run-time setting的brower改 ...
- Java开发利器--Lombok,IDEA端安装教程
1.插件安装File-Setting-Plugins 2.开启注解支持: 3.安装lombok maven插件 <plugin> <groupId>org.projectlom ...
- ELK学习总结(2-2)单模式CRUD操作
------------------------------------------------------ 1.查看索引信息 请求命令: GET /library/_settings GET /li ...
- python tornado TCPserver异步协程实例
项目所用知识点 tornado socket tcpserver 协程 异步 tornado tcpserver源码抛析 在tornado的tcpserver文件中,实现了TCPServer这个类,他 ...