【问题描述】

  小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]严格次小生成树的更多相关文章

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

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

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

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

  3. 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

    非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...

  4. bzoj1977次小生成树(重要)

    #include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...

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

    题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...

  6. 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)

    传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...

  7. bzoj1977 次小生成树

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

  8. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

  9. [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca

    Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...

随机推荐

  1. C++智能指针(auro_ptr...)

    写的很好,忍不住转了: 博文原址:http://blog.csdn.net/xt_xiaotian/article/details/5714477 一.简介 由于 C++ 语言没有自动内存回收机制,程 ...

  2. labview与单片机串口通信

    labview与单片机串口通信   VISA是虚拟仪器软件体系结构的缩写(即Virtual Instruments Software Architecture),实质上是一个I/O口软件库及其规范的总 ...

  3. 第三篇:Python字符编码

    一 .了解字符编码的知识储备 1计算机基础知识 1.2文本编辑器存取文件的原理(nodepat++,Pycharm,word) #.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的 ...

  4. JAVA_SE基础——58.如何用jar命令对java工程进行打包

    有时候为了更方便快捷的部署和执行Java程序,要把java应用程序打包成一个jar包.而这个基础的操作有时候也很麻烦,为了方便java程序员们能够方便的打包java应用程序,下面对jar命令进行介绍, ...

  5. Thinkphp框架部署步骤

    Thinkphp框架部署步骤 thinkphp框架部署起来简单,但是由于步骤较多也容易遗忘: 这是安装了集成环境后的一个www根目录结构: 然后需要在这个目录下面创建一个文件夹做项目:thinkphp ...

  6. 第四章 Ajax与jQuery

    第四章   Ajax与jQuery 一.Ajax简介 在传统的Web应用中,每次请求服务器都会生成新的页面,用户在提交请求后,总是要等待服务器的响应.如果前一个请求没有响应,则后一个请求就不能发送,在 ...

  7. 阿里云API网关(3)快速入门(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  8. docker实践

    我的docker 学习笔记2   ps axf docker run -d cyf:sshd /usr/sbin -D   docker  ps docker-enter.sh 686 ps axf ...

  9. zuul入门(3)开发zuul的过滤器

    1.编写Zuul过滤器(Java&Groovy) 理解过滤器类型和请求生命周期后,我们来编写一个Zuul过滤器.编写Zuul的过滤器非常简单,我们只需继承抽象类ZuulFilter,然后实现几 ...

  10. maven常见问题处理(3-3)Gradle编译时下载依赖失败解决方法

    Gradle编译时在本地仓库中如果没有发现依赖,就会从远程仓库中下载, 默认的远程仓库为 mavenCentral(),即 http://repo1.maven.org/maven2/往往访问速度特别 ...