bzoj2654:tree

传送门

wqs二分果题
就是切线对应多个点有点烦,别的很好想
当切线对应多个点时,就取横坐标最小的决策点,最后取横坐标最大的决策点求答案。
代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
#define rg register
void read(int &x){
    char ch;bool ok=0;
    for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
    for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    if(ok)x=-x;
}
const int maxn=1e5+10;
int f[maxn],n,m,k,ans,num;
struct oo{int x,y,z,id;}a[maxn],g[maxn];
bool cmp(oo a,oo b){return a.z==b.z?a.id>b.id:a.z<b.z;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
bool check(int now){
    for(rg int i=1;i<=n;i++)f[i]=i;
    int tot=0,sum=0;num=0;
    for(rg int i=1;i<=m;i++)g[++tot]=a[i],g[tot].z=!a[i].id?g[tot].z-now:g[tot].z;
    sort(g+1,g+m+1,cmp);
    for(rg int i=1;i<=m;i++)
        if(find(g[i].x)!=find(g[i].y)){
            sum+=(g[i].id==0),num+=g[i].z;
            f[find(g[i].x)]=find(g[i].y);
        }
    return sum<=k;
}
int main(){
    read(n),read(m),read(k);
    for(rg int i=1,x,y,z,op;i<=m;i++){
        read(x),read(y),read(z),read(op);x++,y++;
        a[i]=(oo){x,y,z,op};
    }
    int l=-105,r=105;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1,ans=num+mid*k;
        else r=mid-1;
    }
    printf("%d\n",ans);
}
posted @ 2019-07-06 16:48 蒟蒻--lichenxi 阅读(...) 评论(...) 编辑 收藏