• luogu CF125E MST Company wqs二分 构造


    LINK:CF125E MST Company

    难点在于构造 前面说到了求最小值 可以二分出斜率k然后进行(Kruskal) 然后可以得到最小值。(mx)为值域.

    得到最小值之后还有一个构造问题 值得注意的是虽然得到的权值是最小的 也是合法的 但是此时拿到的边不一定合法。

    出现这种情况的原因是最小生成树的边的权值相等了 所以白边有限那么久多余了。

    实际上可以构造出了的。

    考虑如何构造:

    第一种是考虑最小k度生成树的做法。先将除1以外的联通块做一下。然后不断加边。

    加成一颗树的时候如果不满足k度 那么再次加边 在边形成的这个环中找到除了和1相连的最大边 然后在所有的边中选取影响最小的。

    一直重复是的1的度数为k.每次暴力dfs预处理一下. 复杂度(ncdot k+mlogm)

    值得一提的是这个做法脱离了Wqs二分 比较暴力 但是是一个比较经典的做法。

    第二种是直接替换法。

    二分得到ans之后 所有和1相连的边加上ans 此时可能1的度数cnt>k.

    考虑利用其他边来替换和1相连的那些边 如果一条边的权值和1相连的某条边权值相同 且分属不同子树中就可以替换。

    复杂度(nlogmx+nlogn+mlogm)复杂度算是比较优秀 正确性可以确保。

    第三种是直接构造法。

    还是分析本质原因 边之间的替换问题。

    一个比较重要的结论是最小生成树的边的权值个数是一定的。

    也就是前轮到某个权值 这种权值数量一定。同时可以得到当进行到某一种权值的时候 树的形态也是一定的。可以考虑利用权值分层处理构造。

    设w[x]表示比x大的权值的和1相连的边最多的个数。

    那么当前拿和1相连的边的个数就知道了 直接拿就行了 拿够了就拿其他的边 保证了后续是一定是满足的。

    复杂度(mlogm+nlogmx)

    第三种比较繁琐 第一种不够优秀 所以使用的是第二种方法。

    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 1000000000
    #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-8
    #define sq sqrt
    #define S second
    #define F first
    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=100010,maxn=5010;
    int n,m,k,cnt1,cnt2,cnt,ans,len;
    int f[maxn];set<int>s;
    int lin[maxn],ver[maxn<<1],nex[maxn<<1],e[maxn<<1],v[maxn],e1[maxn],b[maxn];
    inline void add(int x,int y,int z,int z1)
    {
    	ver[++len]=y;nex[len]=lin[x];lin[x]=len;e1[len]=z1;e[len]=z;
    	ver[++len]=x;nex[len]=lin[y];lin[y]=len;e1[len]=z1;e[len]=z;
    	s.insert(z1);
    }
    struct wy
    {
    	int x,y,z,id;
    	inline bool friend operator <(wy a,wy b){return a.z<b.z;}
    }t[maxn],w[maxn],tmp1[MAXN],tmp2[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 void dfs(int x,int fa)
    {
    	f[x]=fa;
    	go(x)if(tn!=fa)dfs(tn,x);
    }
    inline int check(int x)
    {
    	ans=cnt=0;int i=1,j=1;
    	rep(1,n,i)f[i]=i;
    	rep(1,cnt1+cnt2,T)
    	{
    		if(i<=cnt1&&j<=cnt2)
    		{
    			if(t[i].z+x<=w[j].z){if(merge(t[i].x,t[i].y))ans+=t[i].z+x,++cnt;++i;}
    			else {if(merge(w[j].x,w[j].y))ans+=w[j].z;++j;}
    			continue;
    		}
    		if(i<=cnt1){if(merge(t[i].x,t[i].y))ans+=t[i].z+x,++cnt;++i;}
    		else {if(merge(w[j].x,w[j].y))ans+=w[j].z;++j;}
    	}
    	return cnt>=k;
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(m);get(k);
    	rep(1,n,i)f[i]=i;int cc=0;
    	rep(1,m,i)
    	{
    		int get(x),get(y),get(z);
    		if(x==1||y==1)tmp1[++cnt1]=(wy){x,y,z,i};
    		else tmp2[++cnt2]=(wy){x,y,z,i};
    		if(merge(x,y))++cc;
    	}
    	if(cc!=n-1){puts("-1");return 0;}
    	sort(tmp1+1,tmp1+1+cnt1);
    	sort(tmp2+1,tmp2+1+cnt2);
    	rep(1,n,i)f[i]=i;cc=0;
    	rep(1,cnt1,i)if(merge(tmp1[i].x,tmp1[i].y))t[++cc]=tmp1[i];
    	rep(1,n,i)f[i]=i;cnt1=cc;cc=0;
    	rep(1,cnt2,i)if(merge(tmp2[i].x,tmp2[i].y))w[++cc]=tmp2[i];
    	cnt2=cc;int l=-100000,r=100000;
    	if(!check(l)){puts("-1");return 0;}
    	check(r);if(cnt>k){puts("-1");return 0;}
    	while(l+1<r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid))l=mid;
    		else r=mid;
    	}
    	if(check(r))l=r;
    	rep(1,cnt1,i)t[i].z+=l;
    	rep(1,n,i)f[i]=i;ans=cnt=0;int i=1,j=1;
    	rep(1,cnt1+cnt2,T)
    	{
    		if(i<=cnt1&&j<=cnt2)
    		{
    			if(t[i].z<=w[j].z){if(merge(t[i].x,t[i].y))ans+=t[i].z,add(t[i].x,t[i].y,t[i].z,t[i].id),++cnt;++i;}
    			else {if(merge(w[j].x,w[j].y))ans+=w[j].z,add(w[j].x,w[j].y,w[j].z,w[j].id);++j;}
    			continue;
    		}
    		if(i<=cnt1){if(merge(t[i].x,t[i].y))ans+=t[i].z,add(t[i].x,t[i].y,t[i].z,t[i].id),++cnt;++i;}
    		else {if(merge(w[j].x,w[j].y))ans+=w[j].z,add(w[j].x,w[j].y,w[j].z,w[j].id);++j;}
    	}
    	put(n-1);
    	go(1)
    	{
    		dfs(tn,1);
    		f[tn]=tn;
    		b[tn]=e1[i];
    		v[tn]=e[i];
    	}
    	for(int i=1;i<=cnt2;++i)
    	{
    		if(cnt==k)break;
    		int xx=getfather(w[i].x);
    		int yy=getfather(w[i].y);
    		if(xx==yy)continue;
    		if(v[xx]==w[i].z)
    		{
    			f[xx]=yy;
    			s.erase(b[xx]);
    			s.insert(w[i].id);
    			--cnt;
    			continue;
    		}
    		if(v[yy]==w[i].z)
    		{
    			f[yy]=xx;
    			s.erase(b[yy]);
    			s.insert(w[i].id);
    			--cnt;
    		}
    	}
    	for(set<int>::iterator it=s.begin();it!=s.end();++it)printf("%d ",*it);
    	return 0;
    }
    </details>
  • 相关阅读:
    盘点国产数据库墨天轮年终排行(2021)
    python代码格式风格 PEP 8
    python 函数与方法的区别
    【Vue】从搭建环境到使用 VSCode
    如何落地业务建模(1) 业务建模、DDD
    如何落地业务建模(2) 实践DDD时常见的问题
    从落地效果看,如何基于SequoiaDB构建「PB级数据」股份制银行内容管理平台
    开张了
    远程桌面工具mobaxterm
    求职vs招聘交锋中的交流技巧 朱燚:
  • 原文地址:https://www.cnblogs.com/chdy/p/13230947.html
Copyright © 2020-2023  润新知