BZOJ4071: [Apio2015]巴邻旁之桥

首先对于家和公司在同一侧的预处理掉,这样就只剩家和公司不在同一侧的情况了。
if(K==1)ans=∑abs(x-pos)+abs(y-pos);注意到与x,y是否在两侧无关,所以用经典的中位数处理思想sort一遍取中位数贪心即可。
else{
一个人要走的距离是abs(x-pos)+abs(y-pos),让它最短话句话说就是让中点距pos尽可能近,于是我们将所有区间按中点排序,枚举从哪个重中点分成两块,左面走左面的桥右面走右面的桥,平衡树或者权值线段树动态维护中位数即可。
}
好久不写splay,练习了一发…>_<…

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
//by:MirrorGray
using namespace std;
const int N=211111,inf=0x3f3f3f3f;
struct node{
    int x,y;
    node(int a=0,int b=0){
        x=a;y=b;
    }
    bool operator <(const node&b)const{
        return x+y<b.x+b.y;
    }
}a[N];
struct Splay{
    int cnt,root;
    struct splay{int l,r,fa,gs,size,d;ll sum;}sp[N];
    void up(int tr){
        sp[tr].size=sp[tr].gs;
        sp[tr].sum=(ll)sp[tr].d*sp[tr].gs;
        sp[tr].size+=sp[sp[tr].l].size+sp[sp[tr].r].size;
        sp[tr].sum+=sp[sp[tr].l].sum+sp[sp[tr].r].sum;
    }
    Splay(){
        cnt=2;root=1;
        sp[1].d=-inf,sp[2].d=inf;
        sp[1].r=2;sp[2].fa=1;
        sp[1].gs=sp[2].gs=1;
        up(2);up(1);
    }
    void zig(int tr){
        int y=sp[tr].fa;
        sp[y].l=sp[tr].r;
        if(sp[tr].r)sp[sp[tr].r].fa=y;
        sp[tr].fa=sp[y].fa;
        if(sp[y].fa){
            if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=tr;
            else sp[sp[y].fa].r=tr;
        }
        sp[y].fa=tr;sp[tr].r=y;
        up(y);
    }
    void zag(int tr){
        int y=sp[tr].fa;
        sp[y].r=sp[tr].l;
        if(sp[tr].l)sp[sp[tr].l].fa=y;
        sp[tr].fa=sp[y].fa;
        if(sp[y].fa){
            if(sp[sp[y].fa].l==y)sp[sp[y].fa].l=tr;
            else sp[sp[y].fa].r=tr;
        }
        sp[y].fa=tr;sp[tr].l=y;
        up(y);
    }
    void splay(int tr,int aim){
        while(sp[tr].fa!=aim){
            int y=sp[tr].fa;
            if(sp[y].fa==aim){
                if(sp[y].l==tr)zig(tr);
                else zag(tr);
            }
            else{
                if(sp[sp[y].fa].l==y){
                    if(sp[y].l==tr)zig(y),zig(tr);
                    else zag(tr),zig(tr);
                }
                else{
                    if(sp[y].l==tr)zig(tr),zag(tr);
                    else zag(y),zag(tr);
                }
            }
        }
        up(tr);if(!aim)root=tr;
    }
    int pre(int tr,int d,int ret){
        if(!tr)return ret;
        if(sp[tr].d<d)return pre(sp[tr].r,d,tr);
        else return pre(sp[tr].l,d,ret);
    }
    int nxt(int tr,int d,int ret){
        if(!tr)return ret;
        if(sp[tr].d>=d)return nxt(sp[tr].l,d,tr);
        else return nxt(sp[tr].r,d,ret);
    }
    int kth(int tr,int k){
        if(sp[sp[tr].l].size>=k)return kth(sp[tr].l,k);
        if(sp[sp[tr].l].size+sp[tr].gs>=k)return tr;
        return kth(sp[tr].r,k-(sp[sp[tr].l].size+sp[tr].gs));
    }
    void insert(int d){
        int t1=pre(root,d,-1);splay(t1,0);
        int t2=nxt(root,d,-1);splay(t2,t1);
        if(sp[t2].d==d){
            sp[t2].gs++;
            up(t2);up(t1);
            return ;
        }
        sp[t2].l=++cnt;
        sp[cnt].d=d;sp[cnt].fa=t2;sp[cnt].gs=1;
        up(cnt);up(t2);up(t1);
    }
    void del(int d){
        int t1=pre(root,d,-1);splay(t1,0);
        int t2=nxt(root,d+1,-1);splay(t2,t1);
        int tr=sp[t2].l;
        if(sp[tr].gs>1){
            sp[tr].gs--;
            up(tr);up(t2);up(t1);
            return ;
        }
        sp[t2].l=0;
        up(t2);up(t1);
    }
    ll Q(){
        ll ret=0;
        int tr=kth(root,sp[root].size>>1);
        splay(tr,0);int l=sp[tr].l,r=sp[tr].r;
//      cout<<"size : "<<sp[root].size<<" "<<sp[root].sum<<" "<<sp[root].d<<endl;
//      cout<<sp[l].size<<" "<<sp[l].sum+inf<<endl;
//      cout<<sp[r].size<<" "<<sp[r].sum-inf<<endl;
        ret+=(ll)sp[l].size*sp[root].d-sp[l].sum;
        ret+=sp[r].sum-(ll)sp[r].size*sp[root].d;
        ret-=inf<<1;
        return ret;
    }
}t1,t2;

int main(){
    int k,n;scanf("%d%d",&k,&n);
    ll ans=0;int cnt=0;
    for(int i=1;i<=n;i++){
        char s1[2],s2[2];int b,c;
        scanf("%s%d%s%d",s1,&b,s2,&c);
        if(s1[0]==s2[0])ans+=abs(b-c);
        else a[++cnt]=node(b,c),t2.insert(b),t2.insert(c);
    }
    ans+=cnt;
    if(k==1)return printf("%lld\n",ans+t2.Q());
    else{
        sort(a+1,a+1+cnt);
        ll tmp=t1.Q()+t2.Q();
        for(int i=1;i<=cnt;i++){
            t1.insert(a[i].x);t1.insert(a[i].y);
            t2.del(a[i].x);t2.del(a[i].y);
            tmp=min(tmp,t1.Q()+t2.Q());
        }
        printf("%lld\n",ans+tmp);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值