• BZOJ4071 & 洛谷3644 & UOJ112:[APIO2015]巴邻旁之桥——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=4071

    https://www.luogu.org/problemnew/show/P3644

    http://uoj.ac/problem/112

    一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B。

    每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000。相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度。区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对。
    城市中有 N 个居民。第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上。一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 K 座横跨河流的大桥。
    由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。当政府建造最多 K 座桥之后,设 Di 表示第 i 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得 D1+D2+⋯+DN 最小。

    参考:https://www.cnblogs.com/zhenghaotian/p/8304917.html

    对于同岸和走桥的代价先预处理,下面不在阐述。

    k=1时,相当于找到一个点,使得所有起点和终点到该点的距离和最小。则我们排序在中间两点中间建桥则一定最优。就不证明了。

    k=2时不能按k=1做(因为起点和终点需要用的桥是一样的),但是选桥的代价为(A起点,B桥,C终点)A->B->C,显然选一个近的桥最优,用程序表达的话就是离AC中点最近的桥。

    所以以此排序,枚举分界点,其左右都是k=1的情况,用线段树做即可。

    (简单聊下心路历程:开始k=1秒后想k=2,没考虑起点终点桥一样以为三分可过,结果第二个样例就跪了,后来思考之后排序后三分是O(nlog^2n)结果洛谷评测机死活没卡过去TAT果然还是太菜了我)

    #include<cstdio>
    #include<queue>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=200100;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline char getc(){
        char ch=0;
        while(ch!='A'&&ch!='B')ch=getchar();
        return ch;
    }
    struct node{
        int l,r;
    }q[N];
    int m,tot,b[N];
    ll num[2][N*4],sum[2][N*4],L[2],R[2];
    bool cmp(node a,node b){return a.l+a.r<b.l+b.r;}
    void LSH(){
        sort(b+1,b+m+1);
        m=unique(b+1,b+m+1)-b-1;
        for(int i=1;i<=tot;i++){
        q[i].l=lower_bound(b+1,b+m+1,q[i].l)-b;
        q[i].r=lower_bound(b+1,b+m+1,q[i].r)-b;
        }
    }
    void insert(int a,int l,int r,int k,ll w,int p){
        num[p][a]+=w,sum[p][a]+=w*b[k];
        if(l==r)return;
        int mid=(l+r)>>1;
        if(k<=mid)insert(a*2,l,mid,k,w,p);
        else insert(a*2+1,mid+1,r,k,w,p);
    }
    int find(int a,int l,int r,int k,int p){
        if(l==r){
        L[0]+=sum[p][a],L[1]+=num[p][a];
        return b[l];
        }
        int mid=(l+r)>>1;
        if(num[p][a*2]>=k){
        R[0]+=sum[p][a*2+1],R[1]+=num[p][a*2+1];
        return find(a*2,l,mid,k,p);
        }else{
        L[0]+=sum[p][a*2],L[1]+=num[p][a*2];
        return find(a*2+1,mid+1,r,k-num[p][a*2],p);
        }
    }
    int main(){
        int k=read(),n=read();
        ll ans=0;
        for(int i=1;i<=n;i++){
            char ch1=getc();
            ll u=read();
            char ch2=getc();
            ll v=read();
            if(ch1==ch2){
            ans+=abs(u-v);
            continue;
            }
            ans++;
            b[++m]=u,b[++m]=v;
            if(k==2){
            q[++tot]=(node){u,v};
            }
        }
        if(k==1){
            sort(b+1,b+m+1);
            for(int i=1,j=m;i<j;i++,j--)ans+=b[j]-b[i];
            printf("%lld
    ",ans);
        }else{
        if(!tot){
            printf("%lld
    ",ans);
            return 0;
        }
            sort(q+1,q+tot+1,cmp);
        LSH();
        for(int i=1;i<=tot;i++){
            insert(1,1,m,q[i].l,1,1);
            insert(1,1,m,q[i].r,1,1);
        }
        int x=find(1,1,m,tot,1);
        ll tmp=x*L[1]-L[0]+R[0]-x*R[1];
        for(int i=1;i<tot;i++){
            insert(1,1,m,q[i].l,1,0);
            insert(1,1,m,q[i].r,1,0);
            insert(1,1,m,q[i].l,-1,1);
            insert(1,1,m,q[i].r,-1,1);
            ll all=0;
            L[0]=L[1]=R[0]=R[1]=0;
            x=find(1,1,m,i,0);
            all+=x*L[1]-L[0]+R[0]-x*R[1];
            L[0]=L[1]=R[0]=R[1]=0;
            x=find(1,1,m,tot-i,1);
            all+=x*L[1]-L[0]+R[0]-x*R[1];
            tmp=min(tmp,all);
        }
        printf("%lld
    ",ans+tmp);
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    用C++实现网络编程---抓取网络数据包的实现方法
    UNICODE字符串与多字节字符串的转换
    MFC ComboBox的使用
    Windows API学习---线程与内核对象的同步
    Windows API学习---用户方式中的线程同步
    MFC读取XML文件并解析
    Windows API学习---插入DLL和挂接API
    常用[js,css,jquery,html]
    JDBC链接MySQL和Oracle
    使用.NET MVC框架项目开发流程(项目开发流程)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8669351.html
Copyright © 2020-2023  润新知