bzoj 4071 [Apio2015]巴邻旁之桥 splay

来源:互联网 发布:cda数据分析师考试地点 编辑:程序博客网 时间:2024/06/05 19:50

500题留念:
这里写图片描述

对于不过桥的人在最后加进答里就行了。
一个人过桥一定是先从a到桥再从桥到b。

对于K=1的情况,设桥的位置为x,答案就是|a[i]x|+|b[i]x|。因此选在所有a和b的中间最优。
对于K!=1的情况,考虑如果当前点选的桥坐标为x,那么对于这个点,答案是ba+2x(a,b都在桥左),|ba|(a,b跨桥),a+b2x(a,b都在桥右)。
因此可以发现当桥的位置为a+b2 时最优,离a+b2 越远越不优。
因此每个点选离a+b2 最近的桥。将所有点按a+b2 排序。那么一个前缀的点去第一个桥,剩下的后缀的点去第二个桥。
然后在前缀和后缀内用K=1时的方法。
用两个平衡树维护前缀和后缀。支持插入,删除,查询第K大,求子树点到定点的距离(维护区间的size和区间所有点到inf和-inf的距离和)

#include <bits/stdc++.h>using namespace std;#define ll long long#define which(x) (ch[fa[x]][1]==x)const int inf=1e9+10,N=110000;int K,n,cnt;ll ans,fin;char s1[11],s2[11];struct node{    int x,y;    node(){}    node(int x,int y):x(x),y(y){}    friend bool operator < (const node &r1,const node &r2)    {return r1.x+r1.y<r2.x+r2.y;}}a[N];struct Splay{    int cnt,root;    int size[N<<1],ch[N<<1][2],fa[N<<1],val[N<<1],num[N<<1];    ll sl[N<<1],sr[N<<1];    void pushup(int x)    {        sl[x]=sl[ch[x][0]]+sl[ch[x][1]]+(ll)num[x]*(inf+val[x]);        sr[x]=sr[ch[x][0]]+sr[ch[x][1]]+(ll)num[x]*(inf-val[x]);        size[x]=size[ch[x][0]]+size[ch[x][1]]+num[x];    }    Splay()    {        cnt=2;root=1;        ch[1][0]=2;fa[2]=1;        val[2]=-inf;val[1]=inf;        num[1]=num[2]=1;        pushup(2);pushup(1);    }    void rotate(int x)    {        int y=fa[x],k=which(x);        ch[y][k]=ch[x][k^1];        ch[x][k^1]=y;        ch[fa[y]][which(y)]=x;        fa[x]=fa[y];fa[y]=x;        fa[ch[y][k]]=y;        pushup(y);pushup(x);    }    void splay(int x,int tar)    {        while(fa[x]!=tar)        {            int y=fa[x];            if(fa[y]==tar)rotate(x);            else             {                if(which(x)^which(y))                    rotate(x);                else rotate(y);                rotate(x);            }        }        if(!tar)root=x;    }    int find_val(int x,int v)    {        if(val[x]==v)return x;        if(v<val[x])return find_val(ch[x][0],v);        return find_val(ch[x][1],v);    }    int find_kth(int x,int K)    {        if(K>size[ch[x][0]]&&size[ch[x][0]]+num[x]>=K)            return x;        if(size[ch[x][0]]>=K)            return find_kth(ch[x][0],K);        return find_kth(ch[x][1],K-size[ch[x][0]]-num[x]);    }    void up(int x)    {        if(!x)return;        pushup(x);up(fa[x]);    }    void insert(int v)    {        int x=root;        while(1)        {            if(val[x]==v)                {num[x]++;up(x);break;}            if(v<val[x])            {                if(!ch[x][0])                {                    ch[x][0]=++cnt;fa[cnt]=x;                    num[cnt]=size[cnt]=1;val[cnt]=v;                    up(cnt);break;                }                x=ch[x][0];            }            else            {                if(!ch[x][1])                {                    ch[x][1]=++cnt;fa[cnt]=x;                    num[cnt]=size[cnt]=1;val[cnt]=v;                    up(cnt);break;                  }                x=ch[x][1];            }        }        splay(x,0);    }    void del(int v)    {        int x=find_val(root,v);        num[x]--;splay(x,0);    }    ll query()    {        int x=find_kth(root,size[root]/2);        splay(x,0);        return sr[ch[x][0]]-(ll)(inf-val[x])*size[ch[x][0]]        +sl[ch[x][1]]-(ll)(val[x]+inf)*size[ch[x][1]]-        (val[x]+inf)-(inf-val[x]);    }}tr1,tr2;int main(){    //freopen("tt.in","r",stdin);    scanf("%d%d",&K,&n);    for(int i=1,x1,x2;i<=n;i++)    {        scanf("%s%d%s%d",&s1,&x1,&s2,&x2);        if(s1[0]==s2[0])ans+=abs(x1-x2);        else a[++cnt]=node(x1,x2),ans++;    }    sort(a+1,a+1+cnt);    fin=1ll<<60;    for(int i=1;i<=cnt;i++)    {        tr2.insert(a[i].x);        tr2.insert(a[i].y);    }    fin=min(fin,tr1.query()+tr2.query());    if(K==1)return printf("%lld\n",fin+ans),0;    for(int i=1;i<=cnt;i++)    {        tr2.del(a[i].x);        tr2.del(a[i].y);        tr1.insert(a[i].x);        tr1.insert(a[i].y);        fin=min(fin,tr1.query()+tr2.query());    }    printf("%lld\n",ans+fin);    return 0;}
0 0
原创粉丝点击