标签:最大和 生成树 sort wap tor flag 最大值 生成 struct
小蓝书 + 我自己的补充
题意很好理解吧。
设最小生成树的边权之和为 \(sum\)。
我们要找严格次小生成树,就是要找到这样的一条非最小生成树上的边,满足:
所以我们进行如下操作:
显然每次暴查 \(val_1,val_2\) 明显会炸。
所以我们可以运用倍增的思想预处理出点 \(x\) 向上跳 \(2^k\) 次的路径中的 \(val_1\) 和 \(val_2\)。
做法类似与 \(lca\) 倍增做法时维护祖先的做法,这到题我们在找 \(x\) - \(y\) 的路径时也需要 \(lca\) ,所以这两个我们也需要维护出来。
设 \(g[x][k][0/1]\) 表示点 \(x\),向上跳 \(2^k\) 次的路径中的 \(val_1\) 和 \(val_2\)。
转移过程应该很好想,最大值相等从次小值里找最小值,一个更大,从小的最大和大的次小里找次小值。
注意要开 \(long\ long\)
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
const int N = 1e5 + 5;
const int M = 3e5 + 5;
const LL INF = 1e16;
int n,m,f[N][18],t;
LL ans = 0,g[N][18][2],res = INF;
struct E {
int from,to,w; bool is;
E () {
is = false;
}
bool operator < (const E & x) const {
return w < x.w;
}
}e[M];
struct edge {
int head[N],next[M],to[M],w[M],size;
inline void add(int u,int v,int W) {
next[++size] = head[u]; w[size] = W;
to[size] = v; head[u] = size;
next[++size] = head[v]; w[size] = W;
to[size] = u; head[v] = size;
}
inline LL Get_val_2(int y,int j) {
int Fa = f[y][j - 1]; LL Ans;
if(g[y][j - 1][0] == g[Fa][j - 1][0])
Ans = max(g[y][j - 1][1],g[Fa][j - 1][1]);
else if(g[y][j - 1][0] < g[Fa][j - 1][0])
Ans = max(g[y][j - 1][0],g[Fa][j - 1][1]);
else Ans = max(g[y][j - 1][1],g[Fa][j - 1][0]);
return Ans;
}
queue<int> q; int dep[N]; LL dis[N];
void bfs(int s) {
q.push(s); dep[s] = 1;
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; i; i = next[i]) {
int y = to[i];
if(dep[y]) continue;
dep[y] = dep[x] + 1;
dis[y] = dis[x] + w[i];
f[y][0] = x;
g[y][0][0] = w[i]; g[y][0][1] = -INF;
for(int j = 1; j <= t; j++) {
f[y][j] = f[f[y][j - 1]][j - 1];
g[y][j][0] = max(g[y][j - 1][0],g[f[y][j - 1]][j - 1][0]);
g[y][j][1] = max(g[y][j][1],Get_val_2(y,j));
}
q.push(y);
}
}
}
inline LL Get(int x,int y,int w) {
if(dep[x] > dep[y]) swap(x,y);
LL val_1 = 0,val_2 = 0;
for(int i = t; i >= 0; i--)
if(dep[f[y][i]] >= dep[x]) {
val_1 = max(val_1,g[y][i][0]);
if(i > 0) val_2 = max(val_2,Get_val_2(y,i));
y = f[y][i];
}
if(x == y) {
if(w > val_1) return ans - val_1 + w;
if(w == val_1) return ans - val_2 + w;
}
for(int i = t; i >= 0; i--)
if(f[x][i] != f[y][i]) {
val_1 = max(val_1,g[y][i][0]);
if(i > 0) val_2 = max(val_2,Get_val_2(y,i));
val_1 = max(val_1,g[x][i][0]);
if(i > 0) val_2 = max(val_2,Get_val_2(x,i));
x = f[x][i],y = f[y][i];
}
val_1 = max(val_1,g[x][0][0]);
val_1 = max(val_1,g[y][0][0]);
val_2 = max(val_2,max(g[x][0][0],g[y][0][0]));
if(w > val_1) return ans - val_1 + w;
if(w == val_1) return ans - val_2 + w;
}
}a;
int fa[N];
inline int Find(int x) {
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
inline int read() {
int x = 0,flag = 1;
char ch = getchar();
while(ch < ‘0‘ || ch > ‘9‘){if(ch == ‘-‘)flag = -1;ch = getchar();}
while(ch >=‘0‘ && ch <=‘9‘){x = (x << 3) + (x << 1) + ch - 48;ch = getchar();}
return x * flag;
}
int main() {
n = read(),m = read();
t = log(1.0 * n) / log(2.0);
for(int i = 1; i <= m; i++) {
e[i].from = read();
e[i].to = read();
e[i].w = read();
}
for(int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1,e + 1 + m); a.size = 1;
for(int i = 1; i <= m; i++) {
int x = Find(e[i].from);
int y = Find(e[i].to);
if(x == y) continue;
fa[x] = y; ans += e[i].w;
a.add(e[i].from,e[i].to,e[i].w); e[i].is = true;
}
a.bfs(1);
for(int i = 1; i <= m; i++) {
if(e[i].is) continue;
res = min(res,a.Get(e[i].from,e[i].to,e[i].w));
}
printf("%lld\n",res);
return 0;
}
标签:最大和 生成树 sort wap tor flag 最大值 生成 struct
原文地址:https://www.cnblogs.com/sjzyh/p/14826151.html