1977: [BeiJing2010组队]次小生成树 Tree
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 2777 Solved: 695
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
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 。
这道题要求严格的次小MST,思路差不多,但是不能只记录max,还要记录次大值max2,更新的时候分情况讨论,具体看代码。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
const LL INF=(1ll<<60);
const int maxn = 100005;
const int maxm = 300005;
struct Edge
{
int to,next;
int val;
}edge[maxn<<1]; // set for the MST
int head[maxn];
int maxedge;
inline void addedge(int u,int v,int c)
{
edge[++maxedge] = (Edge) { v,head[u],c };
head[u] = maxedge;
edge[++maxedge] = (Edge) { u,head[v],c };
head[v] = maxedge;
}
struct Road
{
int u,v;
int c;
bool operator < (const Road t) const
{
return c < t.c;
}
}road[maxm];
bool used[maxm];
int n,m;
LL MST;
int fa[maxn];
int find(int x) { return fa[x]^x? fa[x]=find(fa[x]) : x ; }
inline bool union_find(int x,int y)
{
int t1=find(x),t2=find(y);
if(t1==t2) return false;
fa[t2]=t1;
return true;
}
LL kruskal()
{
int tot = 0;
LL ans = 0ll;
for(int i=1;i<=m;i++)
{
if(union_find(road[i].u,road[i].v)) tot++,ans+=road[i].c,addedge(road[i].u,road[i].v,road[i].c),used[i]=true;
if(tot==n-1) break;
}
return ans;
}
#define maxd 25
#define D 20
int f[maxn][maxd];
int dp[maxn][maxd][2];
int depth[maxn];
void dfs(int u,int father,int dep)
{
depth[u] = dep;
for(int k=1;k<=D;k++)
{
f[u][k] = f[f[u][k-1]][k-1];
dp[u][k][0] = max(dp[u][k-1][0],dp[f[u][k-1]][k-1][0]);
if(dp[u][k-1][0] == dp[f[u][k-1]][k-1][0]) dp[u][k][1] = max(dp[u][k-1][1],dp[f[u][k-1]][k-1][1]);
else
{
dp[u][k][1] = min(dp[u][k-1][0],dp[f[u][k-1]][k-1][0]);
smax(dp[u][k][1] , max(dp[u][k-1][1],dp[f[u][k-1]][k-1][1]));
}
}
for(int i=head[u];~i;i=edge[i].next)
{
int v = edge[i].to;
if(v==father) continue;
f[v][0] = u;
dp[v][0][0] = (LL)edge[i].val;
// provided two number differs!
dfs(v,u,dep+1);
}
}
inline void merge(int &ans1,int &ans2,int u,int k)
{
int t1 = max(ans1,dp[u][k][0]) , t2;
if(ans1 == dp[u][k][0]) t2 = max(ans2,dp[u][k][1]);
else
{
t2 = min(ans1,dp[u][k][0]);
smax(t2,max(ans2,dp[u][k][1]));
}
ans1 = t1;
ans2 = t2;
}
pair <int,int> query(int u,int v)
{
int ans1 = 0;
int ans2 = 0;
if(depth[u]<depth[v]) swap(u,v);
for(int k=D;k>=0;k--) if(depth[f[u][k]]>=depth[v])
{
merge(ans1,ans2,u,k);
u = f[u][k];
}
if(u==v) return make_pair(ans1,ans2);
for(int k=D;k>=0;k--) if(f[u][k] ^ f[v][k])
{
merge(ans1,ans2,u,k); u=f[u][k];
merge(ans1,ans2,v,k); v=f[v][k];
}
merge(ans1,ans2,u,0); merge(ans1,ans2,v,0);
return make_pair(ans1,ans2);
}
void init()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
maxedge=-1;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++) scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].c);
sort(road+1,road+m+1);
MST=kruskal();
dfs(1,-1,0);
}
LL work()
{
LL subMST=INF;
for(int i=1;i<=m;i++) if(!used[i])
{
pair <int,int> tmp = query(road[i].u,road[i].v);
if(road[i].c ^ tmp.first) smin(subMST,MST - tmp.first + road[i].c);
else smin(subMST,MST - tmp.second + road[i].c);
}
return subMST;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("unique.in","r",stdin);
freopen("unique.out","w",stdout);
#endif
init();
printf(AUTO,work());
return 0;
}