zoukankan      html  css  js  c++  java
  • P2619 [国家集训队]Tree I

    题目

    P2619 [国家集训队]Tree I

    分析

    经典 wqs二分。

    wqs二分的本质是:首先看出答案对于个数 (k) 有单调性,是个凸包。

    然后把“凸包”投射到“y轴”上,此时我们要求这个凸包的顶端必须是取到题目限制的 (k) 个时可以取到最大/小值,如果是 (k+c) 或者 (k-c) 取到最大,则继续二分。

    当正好取到 (k) 最大,停止二分,这样就使得我们既刚好取到 (k) 个又可以取到我们希望的最优解。

    这里也是一样,我们对于白边多加权值进行限制即可。

    但是注意:我们可以把白边黑边先分别储存,每次更新完白色就归并起来,这样可以省掉一个 (sort)(log)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    //#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //char buf[1<<21],*p1=buf,*p2=buf;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const int N=5e5+5;
    const ll INF=1e9;
    int n,m,k,s;
    struct Edge{
    	int u,v,col;ll w;
    	inline bool operator < (const Edge &B)const{return w<B.w;}
    	Edge(int u=0,int v=0,ll w=0,int col=0):u(u),v(v),w(w),col(col){}
    }E1[N],E2[N],E[N];
    int fa[N],top1,top2;
    int Getfa(int x){return fa[x]==x?x:fa[x]=Getfa(fa[x]);}
    ll sum,tot,cnt;
    bool Kruskal(ll mid){
    	tot=sum=m=cnt=0;
    	for(int i=1;i<=n;i++) fa[i]=i;
    	for(int i=1;i<=top1;i++) E1[i].w+=mid;
    	int j=1;
    	for(int i=1;i<=top2;i++){
    		while(j<=top1&&E1[j].w<=E2[i].w) E[++m]=E1[j],j++;
    		E[++m]=E2[i];
    	}
    	while(j<=top1) E[++m]=E1[j++];
    	for(int i=1;i<=m;i++){
    		int u=Getfa(E[i].u),v=Getfa(E[i].v);
    		if(u==v) continue;
    		fa[u]=v;sum+=E[i].w;
    		if(E[i].col==0) tot++;
    		if(cnt==n-1) return tot>=k;
    	}
    	for(int i=1;i<=top1;i++) E1[i].w-=mid;
    	return tot>=k;
    }
    signed main(){
    	read(n),read(m);read(k);
    	for(int i=1,u,v,w,col;i<=m;i++){
    		read(u),read(v),read(w),read(col);
    		u++,v++;
    		if(col==0) E1[++top1]=Edge(u,v,w,col);
    		else E2[++top2]=Edge(u,v,w,col);
    	}
    	
    	sort(E1+1,E1+top1+1),sort(E2+1,E2+top2+1);
    	ll l=-INF,r=INF,ans=-1;
    	while(l<r){
    		ll mid=l+r+1>>1;
    		if(Kruskal(mid)) l=mid;
    		else r=mid-1;
    	}
    	Kruskal(r);
    	write(sum-min(k,(int)tot)*r);
    	return 0;
    }
    
  • 相关阅读:
    自定义事件的触发dispatchEvent
    [转]ProxmoxVE 干掉 VMware
    【转】怎么去阅读Chromium的源码?
    Delphi内存专题
    Delphi 线程同步技术(转)
    【纸模】六角大王 Super 5.6 CHS 简体中文版 U20080725+[手册]窗口与工具的概要(PDF格式)
    ReSharper反编译C#类库
    CS DevExpress程序启动(主窗体初始化优化)
    【EasyNetQ】- 发布/订阅模式
    Intellij Idea调试java文件时 怎么跳过class文件?
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15168019.html
Copyright © 2011-2022 走看看