LINK:最小度限制生成树
还是WQS二分的模板题 不过相当于我WQS二分的复习题.
对于求出强制k个的答案 dp能做不过复杂度太高了。
世界上定义F(x)表示选出x个的答案 画成图像 其实形成了一个凸包。
利用斜率就可以去切这个凸包了。
二分这个斜率 不断的在凸包上切 知道值刚好等于题目中要求的k 有的时候可能会出现mid时为k-1 mid+1时是k的情况 此时可以优先白边选使得在mid时满足要求。
可能此时x>k的 不过可以证明可以构造出来k条边的情况 然后减掉这k条边的权值即可。
卡了下常 跑的挺快的。
code
//#include<bitsstdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 100000000
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d
",x)
#define putl(x) printf("%lld
",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-9
#define sq sqrt
#define mod 998244353
#define S second
#define F first
#define op(x) t[x].op
#define d(x) t[x].d
#define Set(a,v) memset(a,v,sizeof(a))
#define pf(x) ((x)*(x))
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=500010,maxn=50010;
int n,m,s,k,cnt1,cnt2,cnt,all,ans;ll res;
int f[maxn];
struct wy
{
int x,y,z;
inline bool friend operator <(wy a,wy b){return a.z<b.z;}
}t[MAXN],w[maxn],tmp[MAXN];
inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
inline bool merge(int x,int y)
{
int xx=getfather(x);
int yy=getfather(y);
if(xx==yy)return 0;
f[xx]=yy;return 1;
}
inline bool check(int x)
{
int i=1,j=1;
cnt=0,all=0;res=0;
rep(1,n,i)f[i]=i;
rep(1,m,v)
{
if(i<=cnt1&&j<=cnt2)
{
if(t[i].z-x<=w[j].z)
{
if(merge(t[i].x,t[i].y))++cnt,res+=t[i].z-x,++all;
++i;
}
else
{
if(merge(w[j].x,w[j].y))res+=w[j].z,++all;
++j;
}
continue;
}
if(i<=cnt1){if(merge(t[i].x,t[i].y))++cnt,res+=t[i].z-x,++all;++i;}
if(j<=cnt2){if(merge(w[j].x,w[j].y))res+=w[j].z,++all;++j;}
if(all==n-1)break;
}
return cnt>=k;
}
signed main()
{
//freopen("1.in","r",stdin);
get(n);get(m);get(s);get(k);
rep(1,n,i)f[i]=i;
rep(1,m,i)
{
int get(x),get(y),get(z);
if(x==s||y==s)t[++cnt1]=(wy){x,y,z};
else tmp[++cnt2]=(wy){x,y,z};
ans+=merge(x,y);
}
if(cnt1<k){puts("Impossible");return 0;}
if(ans!=n-1){puts("Impossible");return 0;}
rep(1,n,i)f[i]=i;
sort(t+1,t+1+cnt1);
sort(tmp+1,tmp+1+cnt2);
int ww=0;
rep(1,cnt2,i)if(merge(tmp[i].x,tmp[i].y))w[++ww]=tmp[i];
cnt2=ww;
int l=-INF,r=INF;
if(!check(r)){puts("Impossible");return 0;}
if(check(l)&&cnt!=k){puts("Impossible");return 0;}
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
check(l);
putl(res+(ll)k*l);return 0;
}