次小生成树
有意思的题QwQ 写一下博客QwQ
P4180\ [BJWC2010] 严格次小生成树
题目描述
小 C 最近学了很多最小生成树的算法,Prim 算法、Kruskal 算法、消圈算法等等。正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
对于次小生成树,我们知道它就是最小生成树噶掉一个边再加上一个边。枚举加上的这个边。
这里有个图,图上的是最小生成树,我们枚举边枚举到
code:
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
const int inf = 11451419198101919;
bool used[314514];
int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + (c^48),c = getchar();
return x*f;
}
int pa[314514],n,m;
struct edge {
int u,v,w;
bool operator<(edge b) const {
return w < b.w;
}
}edges[311541];
int head[314514],nxt[311541],wei[311541],to[311541],cnt,crom;
void add(int u,int v,int w) {
cnt++;
wei[cnt] = w;
to[cnt] = v;
nxt[cnt] = head[u];
head[u] = cnt;
}
int find(int k) {
if(pa[k] == k) return k;
return (pa[k] = find(pa[k]));
}
int kruskal() {
int num = 0;
int ans = 0;
for(int i = 1; i <= n; i++) {
pa[i] = i;
}
sort(edges+1,edges+m+1);
for(int i = 1; i <= m; i++) {
int x = find(edges[i].u);
int y = find(edges[i].v);
int w = edges[i].w;
if(x == y) continue;
pa[x] = y,ans += w,used[i] = 1;
add(edges[i].u,edges[i].v,w);
add(edges[i].v,edges[i].u,w);
if(++num == n-1) {
break;
}
}
return ans;
}
//krust
int dip[314514],jntm[314514],smg[314514],ikun[314514],siz[314514],child[314514],father[314514],top[314514],tot = 0;
void dfs(int now,int pa) {
siz[now] = 1;
father[now] = pa;
dip[now] = dip[pa]+1;
for(int i = head[now]; i; i = nxt[i]) {
if(to[i] == pa) continue;
dfs(to[i],now);
siz[now] += siz[to[i]];
jntm[to[i]] = wei[i];
if(siz[to[i]] > siz[child[now]]) child[now] = to[i];
}
}
void dfs2(int now,int tp) {
top[now] = tp;
smg[now] = ++tot;
ikun[smg[now]] = jntm[now];
if(!child[now]) return;
dfs2(child[now],tp);
for(int i = head[now]; i; i = nxt[i]) {
if(to[i] != father[now] && to[i] != child[now]) {
dfs2(to[i],to[i]);
}
}
}
int cmp(int a,int b) {return a>b;}
int treeb[314514],trees[314514];
int max2(int a,int b,int c,int d) {
int cop[4];
cop[0] = a;
cop[1] = b;
cop[2] = c;
cop[3] = d;
sort(cop,cop+4,cmp);
for(int i = 1; i < 3; i++) {
if(cop[i] != cop[0]) {
return cop[i];
}
}
return cop[0];
}
void build(int k = 1,int l = 1,int r = n) {
if(l == r) {
treeb[k] = ikun[l];
return ;
}
int mid = (l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
treeb[k] = max(treeb[k<<1],treeb[k<<1|1]);
trees[k] = max2(treeb[k<<1],trees[k<<1],treeb[k<<1|1],trees[k<<1|1]);
}
pair<int,int> query(int x,int y,int k = 1,int l = 1,int r = n) {
if(x <= l && r <= y) return make_pair(treeb[k],trees[k]);
if(y < l || r < x) return make_pair(-inf,-inf);
int mid = (l+r)>>1;
pair<int,int> p1 = query(x,y,k<<1,l,mid),p2 = query(x,y,k<<1|1,mid+1,r);
return make_pair(max(p1.first,p2.first),max2(p1.first,p2.first,p1.second,p2.second));
}
int chop(int u,int v,int w) {
int mx = -inf;
while(top[u] != top[v]) {
if(dip[top[u]] < dip[top[v]]) swap(u,v);
pair<int,int> p = query(smg[top[u]],smg[u]);
u = father[top[u]];
mx = max(mx,(p.first == w)?p.second:p.first);
}
if(dip[u] < dip[v]) swap(u,v);
pair<int,int> p = query(smg[v]+1,smg[u]);
return max(mx,(p.first == w)?p.second:p.first);
}
//"deep cuts"
signed main() {
n = read();
m = read();
for(int i = 1; i <= m; i++) {
int u,v,w;
cin >> u >> v >> w;
edges[i].u = u;
edges[i].v = v;
edges[i].w = w;
}
int cns = kruskal();
dfs(1,0);
dfs2(1,1);
build(1,1,n);
int ans = inf;
for(int i = 1; i <= m; i++) {
if(!used[i]) {
int tmp = cns+edges[i].w-chop(edges[i].u,edges[i].v,edges[i].w);
//cout << tmp << endl;
if(ans > tmp && tmp != cns + edges[i].w && tmp > cns) ans = tmp;
}
}
cout << ans;
return 0;
}