首页 > 代码库 > BZOJ1977: [BeiJing2010组队]次小生成树 Tree

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

 

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