bzoj4367 [IOI2014]holiday假期

题目描述

题解:

很明显总体路径可以是一直向左/向右,或者先向一个方向跑几步,然后反向跑。

所以我们可以得到四种基本运动方式:

LGL:一直向左;

RGR:一直向右;

LGR:先向左,然后向右回到原点;

RGL:先向右,然后向左回到原点。

然后决策单调,分治求解上面四个东西,最后合并出结果。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
#define ll long long
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,st,d,a[N];
ll to[N];
struct Pair
{
    int x,id;
}p0[N];
bool cmp(Pair a,Pair b)
{
    return a.x<b.x;
}
struct ptree
{
    int rt[N],tot,siz[N*20],ch[N*20][2];
    ll vl[N*20];
    void insert(int l,int r,int &u,int br,int qx,ll d)
    {
        u=++tot;
        ch[u][0]=ch[br][0],ch[u][1]=ch[br][1],siz[u]=siz[br]+1,vl[u]=vl[br]+d;
        if(l==r)return ;
        int mid = (l+r)>>1;
        if(qx<=mid)insert(l,mid,ch[u][0],ch[br][0],qx,d);
        else insert(mid+1,r,ch[u][1],ch[br][1],qx,d);
    }
    void build()
    {
        for(int i=1;i<=n;i++)
            insert(1,n,rt[i],rt[i-1],a[i],to[a[i]]);
    }
    ll query(int l,int r,int ul,int ur,int k)
    {
        if(siz[ur]-siz[ul]<=k)return vl[ur]-vl[ul];
        if(l==r)return vl[ur]/siz[ur]*k;
        int mid = (l+r)>>1;
        if(siz[ch[ur][1]]-siz[ch[ul][1]]>=k)return query(mid+1,r,ch[ul][1],ch[ur][1],k);
        else return vl[ch[ur][1]]-vl[ch[ul][1]]+query(l,mid,ch[ul][0],ch[ur][0],k-(siz[ch[ur][1]]-siz[ch[ul][1]]));
    }
    ll ask(int ul,int ur,int k)
    {
        if(k<=0)return 0;
        return query(1,n,rt[ul],rt[ur],k);
    }
}tr;
ll lgl[N<<2],rgr[N<<2],lgr[N<<2],rgl[N<<2];
void LGL(int l1,int r1,int l2,int r2)
{
    int mid = (l1+r1)>>1;
    int pos=l2;ll now = 0;
    for(int i=l2;i<=r2;i++)
    {
        ll tmp = tr.ask(i-1,st-1,mid-st+i);
        if(tmp>=now)
        {
            now=tmp;
            pos=i;
        }
    }
    lgl[mid] = now;
    if(l1<mid)LGL(l1,mid-1,pos,r2);
    if(r1>mid)LGL(mid+1,r1,l2,pos);
}
void RGR(int l1,int r1,int l2,int r2)
{
    int mid = (l1+r1)>>1;
    int pos=l2;ll now = 0;
    for(int i=l2;i<=r2;i++)
    {
        ll tmp = tr.ask(st,i,mid-i+st);
        if(tmp>=now)
        {
            now=tmp;
            pos=i;
        }
    }
    rgr[mid] = now;
    if(l1<mid)RGR(l1,mid-1,l2,pos);
    if(r1>mid)RGR(mid+1,r1,pos,r2);
}
void LGR(int l1,int r1,int l2,int r2)
{
    int mid = (l1+r1)>>1;
    int pos=l2;ll now = 0;
    for(int i=l2;i<=r2;i++)
    {
        ll tmp = tr.ask(i-1,st-1,mid-2*st+2*i);
        if(tmp>=now)
        {
            now=tmp;
            pos=i;
        }
    }
    lgr[mid] = now;
    if(l1<mid)LGR(l1,mid-1,pos,r2);
    if(r1>mid)LGR(mid+1,r1,l2,pos);
}
void RGL(int l1,int r1,int l2,int r2)
{
    int mid = (l1+r1)>>1;
    int pos=l2;ll now = 0;
    for(int i=l2;i<=r2;i++)
    {
        ll tmp = tr.ask(st,i,mid-2*i+2*st);
        if(tmp>=now)
        {
            now=tmp;
            pos=i;
        }
    }
    rgl[mid] = now;
    if(l1<mid)RGL(l1,mid-1,l2,pos);
    if(r1>mid)RGL(mid+1,r1,pos,r2);
}
int main()
{
//  freopen("4.in","r",stdin);
    n=rd(),st=rd()+1,d=rd();
    for(int i=1;i<=n;i++)p0[i].x=rd(),p0[i].id=i;
    sort(p0+1,p0+1+n,cmp);
    for(int las=-1,k=0,i=1;i<=n;i++)
    {
        if(las!=p0[i].x)
        {
            las=p0[i].x;
            to[++k]=las;
        }
        a[p0[i].id]=k;
    }
    tr.build();
    LGL(1,d,1,st);
    LGR(1,d,1,st);
    RGL(1,d,st,n);RGR(1,d,st,n);
    ll ans = 0;
    for(int i=0;i<=d;i++)
        ans=max(ans,max(lgl[i]+rgl[d-i],rgr[i]+lgr[d-i]));
    for(int i=0;i<d;i++)
        ans=max(ans,max(lgl[i]+rgl[d-i-1],rgr[i]+lgr[d-i-1])+to[a[st]]);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2019-01-04 10:01  LiGuanlin  阅读(173)  评论(0编辑  收藏  举报