CF125E MST Company(题解)
P.S.
安利自己的wqs二分学习笔记
本着复习 wqs二分 的目的,我点开了这道题,结果呢。。。。。。
为了纪念来之不易的 AC,我打算写一篇题解。
不过看题解区吵地很厉害,我也不敢肯定这篇题解一定是对的,如果伪了还请原谅。
Description.
此题 输出方案。
Solution.
wqs 二分模板题。
我们把和 1 连边的点当作特殊物品。
然后按照套路二分斜率,每次判定对于和 1 相连的边跑一遍最短路。
由上文,我们每次直接对和 1 相邻边的权值加上当前二分的 mid。
判断有几条边和 1 相连,直接根据这个数量继续二分就好了。
小 tips:每次二分需要求一个 Kruskra,但是我们并不需要对于每次二分重新排序边。
我们只需要刚开始排序一遍,对于每次二分直接归并一下就好了。
于是,成功把复杂度从
UpDate: 笔者偷懒,懒得写归并,直接sort,复杂度两只
然后以 904ms 的优异成绩通过了此题。
主要还需要介绍一些笔者出错的地方。
- 注意二分精度,建议二分到 double
- 开 long long
- 数据范围,边数量和点数量不同
不过没人和笔者这样sb吧 - 二分也需要二分到 +/-,值域需要大一点
然后就做完了,具体可以看代码。
有少量注释。
Coding.
//愿你和你重要的人能够再次重逢!
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>59;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:0;
}
struct node{int x,y;double w;int id;bool operator<(node b) {return w<b.w;}}e[100005],e1[100005],e2[100005];
int n,m,K,fa[10005],t1,t2;
inline int getf(int x) {return fa[x]==x?x:fa[x]=getf(fa[x]);}
inline char mrg(int x,int y) {x=getf(x),y=getf(y);if(x^y) return fa[x]=y,1;else return 0;}
//↑并查集
inline char check(ll w)
{
for(int i=1;i<=t1;i++) e[i]=e1[i],e[i].w+=w/100000.0;
int cnt=0;for(int i=1;i<=t2;i++) e[i+t1]=e2[i];
sort(e+1,e+m+1);for(int i=1;i<=n;i++) fa[i]=i;//暴力排序
for(int i=1;i<=m;i++) if(mrg(e[i].x,e[i].y)) cnt+=(e[i].x==1||e[i].y==1);
return cnt<=K;//计算有多少个点与 1 相连
}//↑二分check函数
int main()
{
read(n),read(m),read(K),assert(0);ll le=-1e16-7,ri=1e16+7,rs=1e16+7;//值域,尽量大 (assert(0)不解释
for(int i=1,x,y,w;i<=m;i++) {read(x),read(y),read(w);if(x==1||y==1) e1[++t1]=(node){x,y,w,i};else e2[++t2]=(node){x,y,w,i};}
//↑把边分类 ↓wqs二分主体(一行
while(le<=ri) {ll md=(le+ri)/2;if(check(md)) rs=md,ri=md-1;else le=md+1;}
if(!check(rs)) return puts("-1"),0;else printf("%d\n",n-1);
for(int i=1;i<=t1;i++) e[i]=e1[i],e[i].w+=rs/100000.0;
for(int i=1;i<=t2;i++) e[i+t1]=e2[i];
sort(e+1,e+m+1);for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++) if(mrg(e[i].x,e[i].y)) printf("%d ",e[i].id);
return putchar('\n'),0;//↑输出方案,check 直接赋值一遍(
}