P3623 [APIO2008]免費道路 WQS二分

youth518發表於2020-10-30

題意:

題意

分析:

手動給邊權賦值,轉化成 PP2619 [國家集訓隊2]Tree I

程式碼:

#include<bits/stdc++.h>

using namespace std;

namespace zzc 
{
	const int maxn = 2e4+5;
	const int maxm = 100005;
	const double eps = 1e-5;
	int fa[maxn];
	int n,m,need,tot,cnt;
	bool vis[maxm];

	struct edge 
	{
		int frm,to,nxt,flag;
		double val;
	}e[maxm];

	bool cmp(edge a,edge b) 
	{
		if(a.val==b.val) return a.flag<b.flag;
		return a.val<b.val;
	}

	int find(int u) 
	{
		return fa[u]==u?u:fa[u]=find(fa[u]);
	}

	void init() 
	{
		scanf("%d%d%d",&n,&m,&need);
		for(int i=1;i<=m;i++) 
		{
			scanf("%d%d%d",&e[i].frm ,&e[i].to,&e[i].flag);
			e[i].val=rand()%m;
		}
	}
    
    void kruskal()
    {
    	sort(e+1,e+m+1,cmp);
    	for(int i=1;cnt!=n-1;i++)
		{
          int fx=find(e[i].frm),fy=find(e[i].to);
          if(fx!=fy)
		  {
		 	   vis[i]=true;
         	   cnt++;
               fa[fx]=fy;
               if(e[i].flag==0) tot++;
          } 
       }
	}

	void solve() 
	{
		double l=-2e5+5,r=2e5+5;
		while(r-l>=eps) 
		{
			double mid=(l+r)/2.0;
			for(int i=1;i<=m;i++) 
			{
				if(!e[i].flag) e[i].val+=mid;
				vis[i]=false;
			}
			for(int i=1;i<=n+1; i++) fa[i]=i;
			cnt=0,tot=0;
			kruskal();
			if(tot>=need) l=mid+1;
			else r=mid-1;
			if(tot==need)
			{
				for(int i=1;i<=m;i++) if(vis[i]) printf("%d %d %d\n",e[i].frm,e[i].to,e[i].flag);
				return ;
			}
			for(int i=1; i<=m; i++) if(e[i].flag==0)e[i].val-=mid;
		}
		printf("no solution\n");
	}
    
    void work()
    {
    	srand(time(0));
    	init();
    	solve();
	}

}

int main() 
{
	zzc::work();
	return 0;
}

相關文章