[APIO2015]八鄰旁之橋

來源:互聯網
上載者:User

標籤:不用   一個   scan   set   turn   blog   ...   const   abs   

題面在這裡sol

這是一個\(Splay\)的題解
首先,如果一個人的家和辦公室在同一側,我們可以直接預先處理;
如果不在同一側,也可以加上1(當然要過橋啦)

當k==1時

我們設橋的位置為\(pos\),每個人的家的位置為\(x[i]\),辦公室的位置為\(y[i]\),
則總代價為\(\sum_{i=1}^n (abs(x_i-pos)+abs(y_i-pos))\)
從這裡我們可以看到,其實家和辦公室的區別不是很明顯。
所以這個問題可以簡化為:
在數軸上任取一點a,最小化 \(\sum abs(a-x_i)\)
那麼我們將所有家和辦公室按照座標排序,橋的位置肯定就在中間兩個端點的位置之間
至於怎麼統計相信大家都會吧(就在下面)
把所有家和辦公室的座標丟進一棵Splay中,平分
統計出左邊的sum和右邊的sum,左邊的sz和右邊的sz

當k==2時

再將上面的式子細分一下,我們能發現:
對於每條路徑\(x[i]->y[i]\),其實際長度和\(1/2(x[i]+y[i])\)距離橋的距離有關
於是我們可以考慮將所有路徑按照\((x[i]+y[i])\)排序
考慮建立兩顆Splay
首先把所有的節點全部插入一棵Splay中去
然後一對一對(注意此處)的從老Splay中丟到另一棵Splay中去,一邊統計答案
複雜度是O(nlogn)
應該是做完了

什麼!!!!你被卡常了!!!!

在下提交的時候,第二個點總是TLE...交了無數遍的95分
看著機房的其他dalao都是用線段樹做的,並不是很甘心啊......
但是方法總比困難多(hhhh)
具體可以參考My Code
(一遍過的dalao可以略過)

代碼
#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define RG register#define isr(i) (s[1][fa[(i)]]==(i))using namespace std;typedef long long ll;const int N=200010;const int inf=2147483647;int cntt;ll Ans[N];struct line{    int l,r;    bool operator <(const line &a)const{        return (l+r)<(a.l+a.r);    }}t[N];inline int read(){    RG int x=0,w=1;char ch=getchar();    while ((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘) ch=getchar();    if (ch==‘-‘) w=0,ch=getchar();    while (ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();    return w?x:-x;}bool cmp(line a,line b){return (a.l+a.r)<(b.l+b.r);}struct Splay{    int root,tot,j,k;    int s[2][N],fa[N],sz[N],cnt[N];    ll sum[N],v[N];    inline bool empty(){return !(bool)sz[root];}    inline void clear(){        root=tot=0;        memset(s,0,sizeof(s));        memset(fa,0,sizeof(fa));        memset(sz,0,sizeof(sz));        memset(sum,0,sizeof(sum));        memset(cnt,0,sizeof(cnt));        memset(v,0,sizeof(v));    }        inline void init(int i,int x,int ff){        s[0][i]=s[1][i]=0;fa[i]=ff;        v[i]=sum[i]=x;cnt[i]=sz[i]=1;    }        inline void update(int i){        sz[i]=sz[s[0][i]]+sz[s[1][i]]+cnt[i];        sum[i]=sum[s[0][i]]+sum[s[1][i]]+cnt[i]*v[i];    }    inline void rot(int i){        j=fa[i];k=fa[j];        RG bool b=isr(i);        fa[i]=k;s[isr(j)][k]=i;        if(s[!b][i])fa[s[!b][i]]=j;s[b][j]=s[!b][i];        fa[j]=i;s[!b][i]=j;        update(j);    }    inline void splay(int i,int a){        if(!a)root=i;        while(fa[i]^a){            j=fa[i];            if(fa[j]^a)                isr(i)^isr(j)?rot(i):rot(j);            rot(i);        }        update(i);    }    inline void insert(int x){        RG int i=root,ff=0;        while(v[i]!=x&&i){            ff=i;i=s[v[i]<x][i];        }        if(i&&v[i]==x)cnt[i]++;        else{            i=++tot;            if(ff)s[v[ff]<x][ff]=i;            init(i,x,ff);            if(x==inf||x==-inf){                sz[i]=sum[i]=cnt[i]=0;            }        }        splay(i,0);    }    inline int find(int x){        RG int i=root;        while(v[i]!=x&&s[v[i]<x][i])            i=s[v[i]<x][i];        return i;    }        inline void Next(int x,int &lst,int &nxt){        RG int i=find(x);splay(i,0);        if(v[i]>x)nxt=i;        else {            nxt=s[1][i];            while(s[0][nxt])nxt=s[0][nxt];        }        if(v[i]<x)lst=i;        else{            lst=s[0][i];            while(s[1][lst])lst=s[1][lst];        }    }        inline void Delete(int x){        RG int i=find(x);        cnt[i]--;splay(i,0);    }        inline int kth(int k){        RG int i=root;        while(1){            if(sz[s[0][i]]>=k)i=s[0][i];            else if(sz[s[0][i]]+cnt[i]>=k)return i;            else k-=sz[s[0][i]]+cnt[i],i=s[1][i];        }    }        inline ll bridge(){//這裡是統計答案(不開long long可是會炸飛的)        if(empty())return 0;        int i=kth(sz[root]/2);splay(i,0);        return 1ll*sz[s[0][i]]*v[i]-sum[s[0][i]]+sum[s[1][i]]-1ll*sz[s[1][i]]*v[i];    }}A,B;inline ll input(ll n){    RG char p[5],q[5];    RG ll ans=0;RG int s,T;        cntt=0;    A.insert(inf);A.insert(-inf);    B.insert(inf);B.insert(-inf);        for(RG int i=1;i<=n;i++){        scanf("%s",p+1);s=read();        scanf("%s",q+1);T=read();        if(p[1]!=q[1]){            ans++;            t[++cntt].l=s;t[cntt].r=T;        }        else ans+=abs(s-T);    }    sort(t+1,t+cntt+1);    for(RG int i=1;i<=cntt;i++){        A.insert(t[i].l);A.insert(t[i].r);        Ans[i]=A.bridge();        /*            最關鍵的地方就是這裡            直接記錄一個Ans數組表示前i條路徑全部走到一座橋上的答案            之後就不用刪除了,把路徑倒著插入另外一棵線段樹中統計即可         */    }        return ans;}inline void work2(int k,int n){        RG ll ans=input(n);    RG ll minn=Ans[cntt];    if(A.empty()){        printf("%lld\n",ans);        return;    }        for(RG int i=cntt;i>=1;i--){        B.insert(t[i].l);B.insert(t[i].r);        minn=min(minn,Ans[i-1]+B.bridge());        //倒插統計部分    }    printf("%lld\n",minn+ans);}inline void work1(int k,int n){    printf("%lld\n",input(n)+A.bridge());}int main(){    RG int k,n;    k=read();n=read();    if(k^1)work2(k,n);    else work1(k,n);    return 0;}

[APIO2015]八鄰旁之橋

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.