zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",ans+ori);
        return 0;
    }
  • 相关阅读:
    WPF应用程序中获取参数
    访问远程oracle数据库时TNS操作超时
    VS2010不能引用System.Data.OracleClient解决方法
    Windows系统下完全卸载Oracle
    创建WPF单实例应用程序
    Winform 版本信息
    SQL Date Time format
    Union合并数组(去掉重复的项目)
    SQL数据类型nchar,char,varchar与nvarchar区别
    Sql语句 生日提醒
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11081383.html
Copyright © 2011-2022 走看看