BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树
描述:
就是求一个次小生成树的边权和
题解
我们先构造一个最小生成树, 把树上的边记录下来。
然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格次小边 $g_1$
如果$val > g_0$就可以考虑把$g_0$ 替换成$val$ 并记录答案。
如果$val = g_0$ 就把$g_1$替换成$val$ 记录答案。
然后我们就需要快速求出树链上的最小和次小边, 需要用树上倍增求LCA类似的方法求。
定义$g[0][ i ][ j ]$ 表示从$j$ 到第 $2^i$ 辈祖先中的最小边, $g[1][ i ][ j ] $表示从$j$ 到 第$2^i$ 辈祖先中的次小边, 满足以下关系:
1: $g[0][ i ][ j ] = \max( g[0][ i - 1][ j ], g[0][ i - 1][ f[i - 1][ j ]]) $
2 :$ g[1][ i ][ j ] = \max( g[1][ i - 1][ j ], g[1][ i - 1 ][ f[i - 1][ j ]]) $ 当$g[0][i - 1][ j ] = g[0][ i - 1][ f[i - 1][ j ]] $
3: $ g[1][ i ][ j ] = \max(g[0][ i - 1][ j ], g[1][ i - 1][ f[i - 1][ j ]])$ 当$g[0][i - 1][ j ] < g[0][ i - 1][ f[i - 1][ j ]] $
4: $ g[1][ i ][ j ] = \max(g[1][ i - 1][ j ], g[0][ i - 1][ f[i - 1][ j ]])$ 当$g[0][i - 1][ j ] > g[0][ i - 1][ f[i - 1][ j ]] $
倍增求树链上的最小和次小值时同理合并
题解
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rd read()
#define rep(i,a,b) for(register int i = (a); i <= (b); ++i)
#define per(i,a,b) for(register int i = (a); i >= (b); --i)
#define ll long long
using namespace std; const int N = 5e5;
const int inf = ~0U >> ; int n, m;
ll sum, ans = 1e18;
int fa[N], f[][N], g[][][N], dep[N];
int head[N], tot; struct edge {
int nxt, to, val;
}e[N << ]; struct node {
int u, v, val, mk;
}E[N << ]; inline int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar()) if(c == '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} inline void added(int u, int v, int val) {
e[++tot].to = v;
e[tot].nxt = head[u];
e[tot].val = val;
head[u] = tot;
} inline void add(int u, int v, int val) {
added(u, v, val); added(v, u, val);
} inline int fd(int x) {
return fa[x] == x ? x : fa[x] = fd(fa[x]);
} inline int cmp(const node &A, const node &B) {
return A.val < B.val;
} inline void dfs(int u) {
for(int i = head[u]; i; i = e[i].nxt) {
int nt = e[i].to;
if(nt == f[][u]) continue;
f[][nt] = u;
g[][][nt] = e[i].val;
g[][][nt] = -inf;
dep[nt] = dep[u] + ;
dfs(nt);
}
} inline void LCA(int x, int y, int &a, int &b) {
int g0, g1;
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; ~i; --i) if(dep[f[i][x]] >= dep[y]) {
g0 = g[][i][x]; g1 = g[][i][x];
if(g0 == a) b = max(b, g1);
if(g0 > a) b = max(a, g1);
if(g0 < a) b = max(g0, b);
a = max(a, g0);
x = f[i][x];
}
for(int i = ; ~i; --i) if(f[i][x] != f[i][y]) {
g0 = g[][i][x]; g1 = g[][i][x];
if(g0 == a) b = max(b, g1);
if(g0 > a) b = max(a, g1);
if(g0 < a) b = max(g0, b);
a = max(a, g0); g0 = g[][i][y]; g1 = g[][i][y];
if(g0 == a) b = max(b, g1);
if(g0 > a) b = max(a, g1);
if(g0 < a) b = max(g0, b);
a = max(a, g0);
x = f[i][x]; y = f[i][y];
} g0 = g[][][x]; g1 = g[][][x];
if(g0 == a) b = max(b, g1);
if(g0 > a) b = max(a, g1);
if(g0 < a) b = max(g0, b);
a = max(a, g0); g0 = g[][][y]; g1 = g[][][y];
if(g0 == a) b = max(b, g1);
if(g0 > a) b = max(a, g1);
if(g0 < a) b = max(g0, b);
a = max(a, g0);
} int main()
{
n = rd; m = rd;
rep(i, , n) fa[i] = i;
rep(i, , m) {
int u = rd, v = rd, val = rd;
E[i].u = u; E[i].v = v; E[i].val = val; E[i].mk = ;
}
sort(E+, E++m, cmp);
rep(i, , m) {
int x = fd(E[i].u), y = fd(E[i].v);
if(x == y) continue;
sum += E[i].val;
fa[y] = x;
E[i].mk = ;
add(E[i].u, E[i].v, E[i].val);
}
dep[] = ;
dfs();
rep(i, , ) rep(j, , n) {
f[i][j] = f[i - ][f[i - ][j]];
g[][i][j] = max(g[][i - ][j], g[][i - ][f[i - ][j]]);
int tmp = -inf;
if(g[][i - ][j] == g[][i - ][f[i - ][j]]) tmp = max(g[][i - ][j], g[][i - ][f[i - ][j]]);
if(g[][i - ][j] < g[][i - ][f[i - ][j]]) tmp = max(g[][i - ][j], g[][i - ][f[i - ][j]]);
if(g[][i - ][j] > g[][i - ][f[i - ][j]]) tmp = max(g[][i - ][j], g[][i - ][f[i - ][j]]);
g[][i][j] = tmp;
}
rep(i, , m) if(!E[i].mk) {
int x = E[i].u, y = E[i].v, g0 = -inf, g1 = -inf;
LCA(x, y, g0, g1);
if(E[i].val == g0 && g1 != -inf) ans = min(ans, sum + E[i].val - g1);
if(E[i].val > g0) ans = min(ans, sum + E[i].val - g0);
}
printf("%lld\n",ans);
}
BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树的更多相关文章
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...
- 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- bzoj 1977 [BeiJing2010组队]次小生成树 Tree
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 kruscal别忘了先按边权sort.自己觉得那部分处理得还挺好的.(联想到之前某题的 ...
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree 倍增 最小生成树
好吧我太菜了又调了一晚上...QAQ 先跑出最小生成树,标记树边,再用树上倍增的思路,预处理出: f[u][i] :距离u为2^i的祖先 h[u][i][0/1] :距u点在2^i范围内的最长边和次长 ...
- 1977: [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...
- [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 5168 Solved: 1668[S ...
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
随机推荐
- Java8 parallelStream与迭代器Iterator性能
定义一个测试类 public class TestParallelStream { private List<Integer> list; private int size; privat ...
- webpack 中使用 vue-router 注意
//render 会把el指定的容器中所有的内容都清空把#app也会去掉 都在c(app)其中的app组件中展示 所有router-link router-view要写在app这个组件里面 //A ...
- WebAPI 和 webservice接口
1. webservice走HTTP协议和80端口.WebService则类似于bs架构,只需要开发服务器端,不需要开发客户端,客户端只要遵循soap协议,就可以调用. 2. api,用的协议和端口, ...
- mysql 拼接字符
Mysql的查询结果行字段拼接,可以用下面两个函数实现: 1. concat函数 mysql> select concat('1','2','3') from test ; +--------- ...
- 学习-HTML5
@@ 学习HTML5发现对我们开发工作者来说要方便很多,它现在还在发展阶段,在未来肯定会是主流. 我们知道HTML5目的是取代HTML4.01和XHTML1.0标准,他希望能够减少互联网富应用(RIA ...
- numpy中的数学
1.dot,exp v = np.dot(arg1,arg2) #矩阵乘法 v2 = np.exp() # e的-x 次方
- ssh 使用 aws
使用 PuTTY 从 Windows 连接到 Linux 实例 启动您的实例之后,您可以连接到该实例,然后像使用您面前的计算机一样来使用它. 注意 启动实例后,需要几分钟准备好实例,以便您能连接到实例 ...
- Linux下查看编辑二进制文件:hexedit神器
1.如果没有hexedit安装hexedit:2.打开终端输入hexedit filename;3.打开即可用键盘输入字符,用方向键移动,ctrl+w保存,ctrl+x退出:4.详细用法 man he ...
- LibreOJ 6285. 数列分块入门 9
题目链接:https://loj.ac/problem/6285 其实一看到是离线,我就想用莫队算法来做,对所有询问进行分块,但是左右边界移动的时候,不会同时更新数字最多的数,只是后面线性的扫了一遍, ...
- java 测试开发基础知识(类加载,JVM等)
写在开头: 面试的时候别人很可能会问你的java原理,.class load 原理, jvm机制,这些都是Java的底层知识,特整理如下: 1. 首先,编写一个java程序,大家会用ide编写一个例如 ...