【问题描述】

  小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. beta冲刺7-咸鱼

    前言:最后一篇惹.明天就是正式交差了.有点慌-- 昨天的未完成: 用户试用+测评 输入部分的正则式判定 今天的工作: 登陆界面修改 我的社团显示效果优化 部分信息注册后锁定无法修改 其他部分功能优化 ...

  2. C语言博客作业--嵌套循环

    一.PTA实验作业 题目1:7-4 换硬币 2 .设计思路 第一步:定义3个整型变量i,j,k用于循环,定义3个整型变量x,count,total分别用于储存零钱数额,换法个数,硬币数量: 第二步:输 ...

  3. C语言函数2

    一.PTA实验作业 6-3 使用函数判断完全平方数: 1. 本题PTA提交列表: 2. 设计思路: 3.本题调试过程碰到问题及PTA提交列表情况说明: 1.一开始考虑让输入值N去整除一个循环变量i,i ...

  4. 简单的C语言编译器--语义制导翻译

      语法分析是最难写的,而这部分确实最伤脑的.大量的语义动作分析差点把我逼疯.   简而言之,这部分的作用就是在每次归约之后,都进行一些语义动作,最终让我们得到测试程序的三地址码,即中间代码. 1. ...

  5. var 和 let 的异同?

    相同点 声明后未赋值表现一致 不同点 1.使用未声明的变量表现不同 2.变量作用范围不同 3.var可以声明多次 let只能声明一次 let的好处就是当我们在写代码的时候可以避免在不知道的情况下重复声 ...

  6. System.Reflection名称空间下的程序集类Assembly应用.

    利用反射中的程序集类(Assembly--抽象类)动态加载类库(.dll)或者可执行程序(.exe). 优点:①.可以消除if条件的逻辑判断.②.减少内存资源.③.有利于程序扩展. 缺点... 使用静 ...

  7. JAVA_SE基础——50.接口关系下的多态

    接口关系下的多态和继承关系下的多态 相差无几,应该更简单些~ 多态: 父类的引用类型变量指向了子类的对象或者是接口类型的引用类型变量指向了接口实现类 的对象. 实现关系下的多态: 接口  变量  = ...

  8. jenkins简单安装及配置(Windows环境)

    jenkins是一款跨平台的持续集成和持续交付.基于Java开发的开源软件,提供任务构建,持续集成监控的功能,可以使开发测试人员更方便的构建软件项目,提高工作效率. Windows平台下,一般安装方法 ...

  9. Python内置函数(32)——all

    英文文档: all(iterable) Return True if all elements of the iterable are true (or if the iterable is empt ...

  10. Python内置函数(20)——hex

    英文文档: hex(x) Convert an integer number to a lowercase hexadecimal string prefixed with "0x" ...