bzoj 4071

数据范围很重要!!!

首先观察数据范围,发现我们要修的桥的数量只能是一座或两座,因此我们直接讨论即可

对于在河的一侧的人家,显然花费是一定的,直接累计即可

对于在河两侧的人家,显然过河的花费是一定的,直接累计即可

接下来讨论的所有人都在桥的两侧

首先我们假设只有一座桥,位置为$x$,设对于第$i$个人,他家的位置是$a_{i}$,办公室的位置是$b_{i}$,那么代价就是$|x-a_{i}|+|x-b_{i}|$

因此总代价即为$\sum_{i=1}^{n}|x-a_{i}|+|x-b_{i}|$

那么这是一个绝对值函数,很显然在所有$a_{i}$,$b_{i}$的中位数处取得最小值,因此只需排序后取出中位数计算即可

接下来考虑两座桥的情况

我们发现,修建两座桥之后,一个点将选择代价最小的一座桥通过(废话)

设两座桥位置为$x_{1}$,$x_{2}$,而一个家的位置为$a$,办公室位置为$b$(设$a<b$),那么代价即为$min(|a-x_{1}|+|b-x_{1}|,|a-x_{2}|+|b-x_{2}|)$

那么我们考虑在什么情况下$x_{1}$比$x_{2}$更优

显然,$x_{1}$应当比$x_{2}$离$\frac{a+b}{2}$更近一些!

为什么?

假设$x_{1}$比$x_{2}$离$\frac{a+b}{2}$更近,那么如果两者都在区间$[a,b]$内,那么贡献一样

如果只有一个在区间内,那么一定会是$x_{1}$!

如果都不在区间里,不妨设两者在区间同侧,那么整理一下表达式,也就是$min(a+b-2x_{1},a+b-2x_{2})$

也就是$2min(|\frac{a+b}{2}-x_{1}|,|\frac{a+b}{2}-x_{2}|)$

是不就一目了然了?

因此,如果我们把每个询问按照$a+b$排序,那么我们可以枚举分界点,使得分界点左侧的点都走左侧的桥,分界点右侧的点都走右侧的桥

然后用两棵权值线段树维护中位数和权值和即可

贴代码:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#define ll long long
#define rt1 rt<<1
#define rt2 (rt<<1)|1
using namespace std;
const int maxn=200005;
ll rnum[maxn];
map <ll,int> M1,M2;
int my_stack[200005];
char ch;
int n,k;
int cnt=0;
struct Ques
{
    int lp,rp;
    friend bool operator < (Ques a,Ques b)
    {
        return a.lp+a.rp<b.lp+b.rp;
    }
}q[100005];
int ttop=0;
struct Seg_tree
{
    ll siz[maxn<<3],sum[maxn<<3];
    void pushup(int rt)
    {
        siz[rt]=siz[rt1]+siz[rt2],sum[rt]=sum[rt1]+sum[rt2];
    }
    int get_num(int rt,int l,int r,int rk)
    {
        if(l==r)return l;
        int mid=(l+r)>>1;
        if(rk<=siz[rt1])return get_num(rt1,l,mid,rk);
        else return get_num(rt2,mid+1,r,rk-siz[rt1]);
    }
    void update(int rt,int l,int r,int pos,int v)
    {
        if(l==r){siz[rt]+=v;sum[rt]+=v*rnum[l];return;}
        int mid=(l+r)>>1;
        if(pos<=mid)update(rt1,l,mid,pos,v);
        else update(rt2,mid+1,r,pos,v);
        pushup(rt);
    }
    int query_size(int rt,int l,int r,int lq,int rq)
    {
        if(l>=lq&&r<=rq)return siz[rt];
        int mid=(l+r)>>1;
        int s=0;
        if(lq<=mid)s+=query_size(rt1,l,mid,lq,rq);
        if(rq>mid)s+=query_size(rt2,mid+1,r,lq,rq);
        return s;
    }
    ll query_sum(int rt,int l,int r,int lq,int rq)
    {
        if(l>=lq&&r<=rq)return sum[rt];
        int mid=(l+r)>>1;
        ll s=0;
        if(lq<=mid)s+=query_sum(rt1,l,mid,lq,rq);
        if(rq>mid)s+=query_sum(rt2,mid+1,r,lq,rq);
        return s;    
    }
}tr1,tr2;
template <typename T>inline void read(T &x)
{
    T c=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x=c*f;
}
void solve()
{
    ll ori=0;
    for(int i=1;i<=n;i++)
    {
        bool fl1=0,fl2=0;
        ll ql,qr;
        ch=getchar();
        read(ql);
        fl1=(ch=='A');
        ch=getchar();
        read(qr);
        fl2=(ch=='A');
        if(fl1==fl2)ori+=abs(qr-ql);
        else ori++,my_stack[++ttop]=ql,my_stack[++ttop]=qr;
    }
    sort(my_stack+1,my_stack+ttop+1);
    ll temp=my_stack[ttop/2];
    for(int i=1;i<=ttop;i++)ori+=abs(temp-my_stack[i]);
    printf("%lld\n",ori);
}

int main()
{
    read(k),read(n);
    if(k==1){solve();return 0;}
    ll ori=0;
    for(int i=1;i<=n;i++)
    {
        bool fl1=0,fl2=0;
        ll ql,qr;
        ch=getchar();
        read(ql);
        fl1=(ch=='A');
        ch=getchar();
        read(qr);
        fl2=(ch=='A');
        if(fl1==fl2)ori+=abs(qr-ql);
        else 
        {
            ori++,q[++ttop]=(Ques){ql,qr};
            M1[ql]=M1[qr]=1;
        }
    }
    if(!ttop){printf("%lld\n",ori);return 0;}
    sort(q+1,q+ttop+1);
    map <ll,int>::iterator it;
    for(it=M1.begin();it!=M1.end();it++)M2[it->first]=++cnt,rnum[cnt]=it->first;
    for(int i=1;i<=ttop;i++)
    {
        q[i].lp=M2[q[i].lp],q[i].rp=M2[q[i].rp];
        tr2.update(1,1,cnt,q[i].lp,1),tr2.update(1,1,cnt,q[i].rp,1);
    }
    ll ans=0x3f3f3f3f3f3f3f3fll;
    for(int i=1;i<ttop;i++)
    {
        tr1.update(1,1,cnt,q[i].lp,1),tr1.update(1,1,cnt,q[i].rp,1);
        tr2.update(1,1,cnt,q[i].lp,-1),tr2.update(1,1,cnt,q[i].rp,-1);
        int p1=tr1.get_num(1,1,cnt,i),p2=tr2.get_num(1,1,cnt,ttop-i);
        ll v0=0,v1=0;
        v0+=tr1.query_size(1,1,cnt,1,p1)*rnum[p1]-tr1.query_sum(1,1,cnt,1,p1);
        v0+=tr1.query_sum(1,1,cnt,p1,cnt)-tr1.query_size(1,1,cnt,p1,cnt)*rnum[p1];
        v1+=tr2.query_size(1,1,cnt,1,p2)*rnum[p2]-tr2.query_sum(1,1,cnt,1,p2);
        v1+=tr2.query_sum(1,1,cnt,p2,cnt)-tr2.query_size(1,1,cnt,p2,cnt)*rnum[p2];
        ans=min(ans,v0+v1);
    }
    printf("%lld\n",ans+ori);
    return 0;
}

 

posted @ 2019-06-25 10:33  lleozhang  Views(154)  Comments(0Edit  收藏  举报
levels of contents