您的位置:首页 > 其它

【BZOJ 1977】 [BeiJing2010组队]次小生成树 Tree

2015-04-01 22:15 155 查看

1977: [BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec Memory Limit: 512 MB

Submit: 2313 Solved: 544

[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

Sample Output

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

倍增。

求出最小生成树,枚举每一条非树边,用它取代掉环上最大的边最优。

那么相当于求两点到lca的最大边权,直接倍增做。

但是要注意是严格最小生成树,那么这条非树边与环上最大边相同时可能取代掉的是环上的次大边,那么倍增的时候多维护一个严格次大的边即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#define LL long long
#define pa pair<int,int>
#define inf 1000000005
#define M 300000+5
#define N 100000+5
#include <queue>
using namespace std;
queue<int> q;
LL pre=0;
int a[5],fa
,v[M],n,m,tot,h
,d
,f
[21];
struct Edge
{
int x,y,v;
}E[M];
struct edge
{
int y,ne,v;
}e[M*2];
struct ma
{
int a,b;
}g
[21],p;
bool cmp(Edge a,Edge b)
{
return a.v<b.v;
}
int Getfather(int x)
{
return x==fa[x]?x:fa[x]=Getfather(fa[x]);
}
void Kruscal()
{
sort(E+1,E+1+m,cmp);
int cnt=1;
for (int i=1;i<=m;i++)
{
int fx=Getfather(E[i].x),fy=Getfather(E[i].y);
if (fx==fy) continue;
cnt++;
v[i]=1;
fa[fx]=fy;
pre+=E[i].v;
}
}
void Addedge(int x,int y,int v)
{
e[++tot].y=y;
e[tot].ne=h[x];
e[tot].v=v;
h[x]=tot;
e[++tot].y=x;
e[tot].ne=h[y];
e[tot].v=v;
h[y]=tot;
}
void Build()
{
for (int i=1;i<=m;i++)
if (v[i])
Addedge(E[i].x,E[i].y,E[i].v);
g[1][0].a=g[1][0].b=-inf;
f[1][0]=0;
d[1]=1;
q.push(1);
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=h[x];i;i=e[i].ne)
{
int y=e[i].y;
if (y==f[x][0]) continue;
f[y][0]=x;
d[y]=d[x]+1;
g[y][0].a=e[i].v;
q.push(y);
}
}
}
void Update(ma &x,ma y)
{
/*a[0]=x.a,a[1]=x.b,a[2]=y.a,a[3]=y.b;
sort(a,a+4);
x.a=max(x.a,y.a);
for (int k=2;k>=0;k--)
if (a[k]!=a[k+1])
{
x.b=a[k];
break;
}*/
if (x.a>y.a) x.b=max(y.a,x.b);
else if (x.a<y.a) x.b=max(x.a,y.b);
else x.b=max(x.b,y.b);
x.a=max(x.a,y.a);
}
void ST()
{
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
Update(g[i][j],g[i][j-1]);
Update(g[i][j],g[f[i][j-1]][j-1]);
}
}
void Move(int &x,int deep)
{
for (int i=20;i>=0;i--)
if (d[f[x][i]]>=deep)
Update(p,g[x][i]),x=f[x][i];
}
void Getlca(int x,int y)
{
p.a=p.b=-inf;
if (d[x]>d[y]) swap(x,y);
Move(y,d[x]);
if (x==y) return;
for (int i=20;i>=0;i--)
if (f[x][i]!=f[y][i])
{
Update(p,g[x][i]),Update(p,g[y][i]);
x=f[x][i],y=f[y][i];
}
Update(p,g[x][0]),Update(p,g[y][0]);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].v);
for (int i=1;i<=n;i++)
fa[i]=i;
Kruscal();
Build();
ST();
LL ans=(LL)1e15;
for (int i=1;i<=m;i++)
if (!v[i])
{
Getlca(E[i].x,E[i].y);
if (p.a==E[i].v)
ans=min(ans,pre+E[i].v-p.b);
else ans=min(ans,pre+E[i].v-p.a);
}
printf("%lld\n",ans);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: