1977: [BeiJing2010组队]次小生成树 Tree
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3002 Solved: 752
[ Submit][ Status][ Discuss]
Description
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
Input
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
Output
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
Sample Input
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
Sample Output
11
HINT
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
Source
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1E5 + 10;
const int maxm = 3E5 + 30;
const int T = 14;
const int INF = ~0U>>1;
typedef long long LL;
struct E{
int x,y,w; E(){}
E(int x,int y,int w): x(x),y(y),w(w){}
bool operator < (const E &B) const {return w < B.w;}
}edgs[maxm];
struct E2{
int to,w; E2(){}
E2(int to,int w): to(to),w(w){}
};
int n,m,Fr,Sc,delta = INF,fa[maxn][T],F[maxn],L[maxn],fr[maxn][T],sc[maxn][T];
bool bo[maxm]; LL sum;
vector <E2> v[maxn];
int getF(int k) {return k == F[k] ? k : F[k] = getF(F[k]);}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
void Merge(int &nf,int &ns,const int &mf,const int &ms)
{
if (nf == mf) ns = max(ns,ms);
else if (nf > mf) ns = max(ns,mf);
else ns = max(nf,ms),nf = mf;
}
void Dfs(int x,int from)
{
for (int i = 1; i < T; i++)
{
int y = fa[x][i-1]; fa[x][i] = fa[y][i-1];
Merge(fr[x][i],sc[x][i],fr[x][i-1],sc[x][i-1]);
Merge(fr[x][i],sc[x][i],fr[y][i-1],sc[y][i-1]);
}
for (int i = 0; i < v[x].size(); i++)
{
E2 e = v[x][i];
if (e.to == from) continue;
fa[e.to][0] = x; fr[e.to][0] = e.w;
sc[e.to][0] = -INF; L[e.to] = L[x] + 1; Dfs(e.to,x);
}
}
void LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int j = T - 1; j >= 0; j--)
if (L[p] - (1<<j) >= L[q])
Merge(Fr,Sc,fr[p][j],sc[p][j]),p = fa[p][j];
if (p == q) return;
for (int j = T - 1; j >= 0; j--)
if (fa[p][j] != fa[q][j])
{
Merge(Fr,Sc,fr[p][j],sc[p][j]); p = fa[p][j];
Merge(Fr,Sc,fr[q][j],sc[q][j]); q = fa[q][j];
}
Merge(Fr,Sc,fr[p][0],sc[p][0]); Merge(Fr,Sc,fr[q][0],sc[q][0]);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint();
for (int i = 1; i <= m; i++)
{
int x = getint(),y,w;
y = getint(); w = getint();
edgs[i] = E(x,y,w);
}
for (int i = 1; i <= n; i++) F[i] = i;
sort(edgs + 1,edgs + m + 1);
for (int i = 1; i <= m; i++)
{
int fx = getF(edgs[i].x),fy = getF(edgs[i].y);
if (fx == fy) continue;
bo[i] = 1; F[fx] = fy; sum += 1LL * edgs[i].w;
v[edgs[i].x].push_back(E2(edgs[i].y,edgs[i].w));
v[edgs[i].y].push_back(E2(edgs[i].x,edgs[i].w));
}
L[n / 2] = 1; Dfs(n / 2,0);
for (int i = 1; i <= m; i++)
{
if (bo[i]) continue;
Fr = Sc = -INF; LCA(edgs[i].x,edgs[i].y);
if (Fr < edgs[i].w) delta = min(delta,edgs[i].w - Fr);
else if (Sc != -INF) delta = min(delta,edgs[i].w - Sc);
}
cout << 1LL * delta + sum << endl;
return 0;
}