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

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

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2108  Solved: 463
[Submit][Status]

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 。

Source

题解:

真是不能再sb了。。。数组越界+xy打反。。。

如果不是严格的只需要枚举每条边,在MST上找这两点之间最大的边记作x,与当前枚举边的权值记作y,用y-x更新答案即可。

但是如果是严格的话?就会出现y==x的情况,那我们可以不管这条边吗?

当然不行,次小生成树是由MST加上一条边删去另一条边得到的。

想想看如果去掉此时两点间的次大值,加上y,也有可能成为答案。第三大就不会了。

所以我们需要找次大边,分情况来更新答案。

我还有点不懂的地方就是:

不同的两个MST最多有多少条边不同?怎么保证任何一个MST通过本题的操作都能的得到正确的答案?

求神犇指教。

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 1000000000
 13 #define maxn 100000+100
 14 #define maxm 300000+100
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 using namespace std;
 22 inline int read()
 23 {
 24     int x=0,f=1;char ch=getchar();
 25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 27     return x*f;
 28 }
 29 int dep[maxn],fa[maxn],head[maxn],tot,n,m,f[maxn][22];
 30 bool out[maxm];
 31 struct recc{int a,b;} g[maxn][22],ret;
 32 struct edge{int go,next,w;}e[2*maxn];
 33 struct rec{int x,y,z;}a[maxm];
 34 inline void insert(int x,int y,int w)
 35 {
 36     e[++tot].go=y;e[tot].w=w;e[tot].next=head[x];head[x]=tot;
 37     e[++tot].go=x;e[tot].w=w;e[tot].next=head[y];head[y]=tot;
 38 }
 39 inline bool cmp(rec a,rec b)
 40 {
 41     return a.z<b.z;
 42 }
 43 inline void update(recc &x,recc &y)
 44 {
 45     if(y.a<x.a)y.b=y.a,y.a=x.a;
 46         else {if(x.a>y.b&&x.a<y.a)y.b=x.a;}
 47     if(x.b==-1)return;
 48     if(y.a<x.b)y.b=y.a,y.a=x.b;
 49         else {if(x.b>y.b&&x.b<y.a)y.b=x.b;}    
 50 }            
 51 inline void dfs(int x)
 52 {
 53     for1(i,20)
 54      if((1<<i)<=dep[x])
 55       {
 56         f[x][i]=f[f[x][i-1]][i-1];
 57         g[x][i].a=g[x][i].b=-1;  
 58         update(g[f[x][i-1]][i-1],g[x][i]);
 59         update(g[x][i-1],g[x][i]);      
 60       }
 61      else break;
 62     for(int i=head[x],y;i;i=e[i].next)
 63       if(!dep[y=e[i].go])
 64       {
 65         f[y][0]=x;g[y][0].a=e[i].w;g[y][0].b=-1;
 66         dep[y]=dep[x]+1;
 67         dfs(y);
 68       }
 69 }
 70 inline void query(int x,int y)
 71 {
 72     if(dep[x]<dep[y])swap(x,y);
 73     int t=dep[x]-dep[y];
 74     ret.a=ret.b=-1;
 75     for0(i,20)
 76      if(t&(1<<i))
 77       {
 78         update(g[x][i],ret);
 79         x=f[x][i];
 80       }
 81     if(x==y)return;
 82     for(int i=20;i>=0;i--)
 83      if(f[x][i]!=f[y][i])
 84       {
 85           
 86         update(g[x][i],ret);x=f[x][i];
 87         update(g[y][i],ret);y=f[y][i];
 88       }  
 89     update(g[x][0],ret);update(g[y][0],ret); 
 90 }
 91 inline int find(int x)
 92 {
 93     return fa[x]==x?x:fa[x]=find(fa[x]);
 94 }
 95 int main()
 96 {
 97     freopen("input.txt","r",stdin);
 98     freopen("output.txt","w",stdout);
 99     n=read();m=read();
100     for1(i,m)a[i].x=read(),a[i].y=read(),a[i].z=read();
101     sort(a+1,a+m+1,cmp);
102     for1(i,n)fa[i]=i;
103     ll sum=0,ans=inf;
104     for(int i=1,j=1;i<=n-1;i++)
105      {
106         while(find(a[j].x)==find(a[j].y))j++;
107         fa[find(a[j].x)]=find(a[j].y);insert(a[j].x,a[j].y,a[j].z);
108         out[j]=1;
109         sum+=a[j].z;j++;
110      }
111     dep[1]=1;g[1][0].a=g[1][0].b=-1;
112     dfs(1);
113     for1(i,m)if(!out[i])
114     {
115         int x=a[i].x,y=a[i].y,z=a[i].z;query(x,y);
116         if(ret.a!=z&&z-ret.a<ans)ans=z-ret.a;
117         if(ret.a==z&&ret.b!=-1&&z-ret.b<ans)ans=z-ret.b;
118     }
119     printf("%lld\n",ans+sum);
120     return 0;
121 }
View Code

 

posted @ 2014-09-09 19:29  ZYF-ZYF  Views(242)  Comments(0Edit  收藏  举报