bzoj 4071 [Apio2015]巴邻旁之桥

版权声明:辣鸡蒟蒻的blog https://blog.csdn.net/elijahqi/article/details/80345142

http://www.elijahqi.win/archives/3379
Description

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

Input

输入的第一行包含两个正整数 K 和 N,分别表示桥的上限数量和居民的数量。
接下来 N 行,每一行包含四个参数:Pi,Si,Qi 和 Ti,表示第 i 个居民的房子在区域 Pi 的 Si 号建筑上,且他的办公室位于 Qi 区域的 Ti 号建筑上。

Output

输出仅为一行,包含一个整数,表示 D1+D2+⋯+DN 的最小值。

Sample Input
1 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
Sample Output
24
HINT

子任务
所有数据都保证:Pi 和 Qi 为字符 “A” 和 “B” 中的一个, 0≤Si,Ti≤1000000000,同一栋建筑内可能有超过 1 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 1)。

子任务 1 (8 分)
K=1
1≤N≤1000
子任务 2 (14 分)
K=1
1≤N≤100000
子任务 3 (9 分)
K=2
1≤N≤100
子任务 4 (32 分)
K=2
1≤N≤1000
子任务 5 (37 分)
K=2
1≤N≤100000
考虑k=1的时候其实就是求区间中位数 那么排序之后找到中位数之后用前后减减即可
考虑k=2的情况下 每个人的上班路线一定会选择距离(a+b)/2最近的那座桥走
于是我们针对所有人算出这个位置 注意应该按照原位置算这个中点而非离散化后的值
然后我们枚举中间位置即强行划分 左边的属于左边的桥右边的属于右边的桥 然后每次删除点动态加点求区间中位数即可 注意特判如k=2时全在一边的情况

#include<cmath>
#include<cstdio>
#include<cctype>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
#define ll long long 
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while (isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline char getc(){
    char ch=gc();
    while(ch!='A'&&ch!='B') ch=gc();
    return ch;
}
const int N=2e5+10;
struct node1{
    int l,r;
}qr[N>>1];
struct node{
    ll sum;int nm;
}tree[2][N<<2];
ll ans;int q[N],tot,nn,lnm,rnm,n,k;ll ls,rs;
inline bool cmp(const node1 &a,const node1 &b){return a.l+a.r<b.l+b.r;}
inline void insert1(int x,int l,int r,int p,int id,int op){
    tree[id][x].nm+=op;tree[id][x].sum+=q[p]*op;
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) insert1(lc,l,mid,p,id,op);
    if (p>mid) insert1(rc,mid+1,r,p,id,op);
}
inline int query(int x,int l,int r,int id,int p){
    if (l==r) {lnm+=tree[id][x].nm;ls+=tree[id][x].sum;return q[l];}int mid=l+r>>1;
    if (p<=tree[id][lc].nm) {rnm+=tree[id][rc].nm;rs+=tree[id][rc].sum;return query(lc,l,mid,id,p);}
    lnm+=tree[id][lc].nm;ls+=tree[id][lc].sum;return query(rc,mid+1,r,id,p-tree[id][lc].nm);
}
int main(){
    //freopen("bzoj4071.in","r",stdin);
    k=read();n=read();
    for (int i=1;i<=n;++i){
        char cha=getc();int x=read();
        char chb=getc();int y=read();
        if (cha==chb){ans+=abs(y-x);continue;}
        ++ans;qr[++tot]=(node1){x,y};q[++nn]=x;q[++nn]=y;
    }sort(q+1,q+nn+1);
    if (k==1){
        for (int i=1,j=nn;i<j;++i,--j) ans+=q[j]-q[i];
        printf("%lld\n",ans);return 0;
    }nn=unique(q+1,q+nn+1)-q-1;sort(qr+1,qr+tot+1,cmp);
    if (!tot) {printf("%lld\n",ans);return 0;}
    for (int i=1;i<=tot;++i){
        qr[i].l=lower_bound(q+1,q+nn+1,qr[i].l)-q;
        qr[i].r=lower_bound(q+1,q+nn+1,qr[i].r)-q;
        insert1(1,1,nn,qr[i].l,1,1);
        insert1(1,1,nn,qr[i].r,1,1);
    }ll ans1;
    ll t=query(1,1,nn,1,tot);ans1=t*lnm-ls+rs-rnm*t;
    for (int i=1;i<tot;++i){
        insert1(1,1,nn,qr[i].l,0,1);insert1(1,1,nn,qr[i].r,0,1);
        insert1(1,1,nn,qr[i].l,1,-1);insert1(1,1,nn,qr[i].r,1,-1);
        ll tmp1,tmp2;lnm=ls=rnm=rs=0;
        t=query(1,1,nn,0,i);tmp1=t*lnm-ls+rs-rnm*t;
        lnm=ls=rnm=rs=0;
        t=query(1,1,nn,1,tot-i);tmp2=t*lnm-ls+rs-rnm*t;
        ans1=min(ans1,tmp1+tmp2);
    }printf("%lld\n",ans1+ans);
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页