题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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


首先用kruskal做一下最小生成树,把这些边称为“树边”,其余的为”非树边“,将每一条边权为v的非树边加到生成树中,则形成一个环,设环上的最大边和次大边分别为val1,val2,则显然:

当 val1 < v 时 sum + v - val1 就是一个候选答案;

当 val1 = v 时 sum + v - val2 就是一个候选答案;

比较所有的候选答案,最小的即是该题的解。那么问题就转换成:如何求环上的最大边和次大边;

可以用lca来写,f[i][k]表示点i向上跳2的k次方所对应的点,dis1[i][k] 和 dis2[i][k] 分别表示点i向上跳2的k次方所对应的最大边和次大边,则显然:

f[i][k] = f[f[i][k - 1]][k - 1];
dis1[i][k] = max(dis1[i][k - 1],dis1[f[i][k - 1]][k - 1]);
if(dis1[i][k - 1] == dis1[f[i][k - 1]][k - 1])
  dis2[i][k] = max(dis2[i][k - 1],dis2[f[i][k - 1]][k - 1]);
if(dis1[i][k - 1] > dis1[f[i][k - 1]][k - 1])
  dis2[i][k] = max(dis2[i][k - 1],dis1[f[i][k - 1]][k - 1]);
if(dis1[i][k - 1] < dis1[f[i][k - 1]][k - 1])
  dis2[i][k] = max(dis1[i][k - 1],dis2[f[i][k - 1]][k - 1]);

初值为:

f[i][] = father(i);
dis1[i][] = edge.v;
dis2[i][] = -INF(不存在)

最后求一下,时间为(mlogn + mlogm);

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define INF 0x3f3f3f3f
#define MAXN 1000010
#define MAXM 100010 inline int read() {
int x = ,ff = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + (ch ^ );
ch = getchar();
}
return x * ff;
} ll sum = ;
int n,m,tem = INF,tot = ,cnt = ;
int vis[MAXN],fa[MAXN],lin[MAXN],deep[MAXN],f[MAXM][],dis1[MAXM][],dis2[MAXM][];
struct tree {
int x,y,v;
} t[MAXN];
struct edge {
int y,v,next;
} e[MAXN]; inline bool cmp(tree x,tree y) {
return x.v < y.v;
} inline int get(int x) {
return fa[x] == x ? x : (fa[x] = get(fa[x]));
} inline void add(int xx,int yy,int vv) {
e[++tot].y = yy;
e[tot].v = vv;
e[tot].next = lin[xx];
lin[xx] = tot;
} void Kruskal() {
sort(t + ,t + m + ,cmp);
for(int i = ; i <= n; ++i)
fa[i] = i;
for(int i = ; i <= m && cnt < n - ; ++i) {
int x = get(t[i].x),y = get(t[i].y);
if(x != y) {
vis[i] = true;
sum += t[i].v;
fa[x] = y;
cnt++;
add(t[i].x,t[i].y,t[i].v);
add(t[i].y,t[i].x,t[i].v);
}
} } void BFS() {
queue < int > q;
q.push();
deep[] = ;
while(!q.empty()) {
int x = q.front();
q.pop();
for(int i = lin[x],y; i ; i = e[i].next) {
if(deep[y = e[i].y]) continue;
deep[y] = deep[x] + ;
f[y][] = x;
dis1[y][] = e[i].v;
dis2[y][] = -INF;
q.push(y);
for(int j = ; j <= ; ++j) {
f[y][j] = f[f[y][j - ]][j - ];
dis1[y][j] = max(dis1[y][j - ],dis1[f[y][j - ]][j - ]);
if(dis1[y][j - ] == dis1[f[y][j - ]][j - ])
dis2[y][j] = max(dis2[y][j - ],dis2[f[y][j - ]][j - ]);
if(dis1[y][j - ] > dis1[f[y][j - ]][j - ])
dis2[y][j] = max(dis2[y][j - ],dis1[f[y][j - ]][j - ]);
if(dis1[y][j - ] < dis1[f[y][j - ]][j - ])
dis2[y][j] = max(dis1[y][j - ],dis2[f[y][j - ]][j - ]);
} }
}
} int lca(int x,int y) {
if(deep[x] > deep[y]) swap(x,y);
for(int i = ; i >= ; --i)
if(deep[f[y][i]] >= deep[x])
y = f[y][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][];
} void cal(int x, int fa, int v) {
int val1 = , val2 = ;
for(int i = ; i >= ; --i) {
if(deep[f[x][i]] >= deep[fa]) {
if (dis1[x][i] > val1) {
val2 = val1;
val1 = dis1[x][i];
}
val2 = max(val2, dis2[x][i]);
x = f[x][i];
}
}
if (val1 != v) tem = min(tem, v - val1);
else tem = min(tem, v - val2);
} int main() {
n = read();
m = read();
for(int i = ; i <= m; ++i) {
t[i].x = read();
t[i].y = read();
t[i].v = read();
}
Kruskal();
BFS();
for(int i = ; i <= m; ++i)
if(!vis[i]) {
int x = t[k].x,y = t[k].y;
int fat = lca(x,y);
cal(x,fat,v);
cal(y,fat,v);
}
printf("%lld\n",sum + tem);
return ;
}

.

严格次小生成树(lca + 倍增)的更多相关文章

  1. 次小生成树(LCA倍增)

    算法: 求出MST之后枚举每条在MST之外的边 连上之后会出现环 找到环中除加上的边之外权值最大的边 删除该边之后得到一颗新树 做法: 利用LCA倍增地维护最小生成树上两点之间的最大边权 每次枚举在M ...

  2. POJ 1679 The Unique MST:次小生成树【倍增】

    题目链接:http://poj.org/problem?id=1679 题意: 给你一个图,问你这个图的最小生成树是否唯一. 题解: 求这个图的最小生成树和次小生成树.如果相等,则说明不唯一. 次小生 ...

  3. 【bzoj1977】【严格次小生成树】倍增维护链上最大次大值

    (上不了p站我要死了,侵权度娘背锅) Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C ...

  4. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree 倍增 最小生成树

    好吧我太菜了又调了一晚上...QAQ 先跑出最小生成树,标记树边,再用树上倍增的思路,预处理出: f[u][i] :距离u为2^i的祖先 h[u][i][0/1] :距u点在2^i范围内的最长边和次长 ...

  5. P4180 【模板】严格次小生成树[BJWC2010]

    P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...

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

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

  7. 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

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

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

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

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

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

  10. 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

随机推荐

  1. 【转载】“菜”鸟理解.NET Framework(CLI,CLS,CTS,CLR,FCL,BCL)

    既然要学.NET,就要先认识认识她,我不喜欢大段大段文字的东西,自己通过理解,画个图,来看看.NET的沉鱼落雁,闭月羞花之容. 最下层蓝色部分是.NET Framework的基础,也是所有应用软件的基 ...

  2. Dell服务器相关操作

    1. Raid相关: # 删除已有的Raid配置 MegaCli64 -CfgLdDel -LALL -aALL # 获取设备ID和槽号 MegaCli64 -PDList -aALL|egrep ' ...

  3. LVM+NBD实现VM数据备份和迁移

    在云系统的高可用性中,VM层的高可用性尤为关键,其中又涉及到了VM本身数据的备份和迁移的问题.在现有的平台上,每一个VM的数据放在一个单独的LV(逻辑卷)上,VM数据的备份可通过备份其所在的LV来完成 ...

  4. 项目Beta冲刺(团队1/7)

    项目Beta冲刺(团队1/7) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标: 完成项目Beta版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 陈宇 ...

  5. org.hibernate.id.IdentifierGenerationException错误解决方法

    org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before ...

  6. 初识Restful(学习笔记)

    什么是Restful? REST -- Resource Representational State Transfer(表现层状态转移) 本质上是一种优雅的URL表达方式,描述资源的状态和状态的转移 ...

  7. 教你如何配置Ubuntu用于高效、高质量的发送邮件

    本文首发在: http://mengxi.me/how-to-setup-ubuntu-sendmail-to-deliver-email-fast-and-reliable/ 在网站上线后,经常会遇 ...

  8. JavaScript算法题(一) && 数组reduce使用

    可参考Array.reduce用法 1. 请编写getMissingElement函数,返回给定数组中缺少的元素(数组里的元素为0~9,只会缺失一个). Example: getMissingElem ...

  9. JAVA反射改动常量,以及其局限

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/barryhappy/article/details/24442953 问题,以及一个解决方式 今天公 ...

  10. 【转】【录教程必备】推荐几款屏幕录制工具(可录制GIF)

    我们经常会遇到一些场景,需要你向别人展示一些操作或是效果——例如告诉别人某某软件的配置步骤啊.刚设计出来网站的动画效果怎么样啊.某某电影里面的一个镜头多么经典啊.打得大快人心的NBA绝杀瞬间是怎么回事 ...