Noip2012 开车旅行

题目链接:Click here

Solution:

注意到每个点的决策都是一定的,我们排序后通过双向链表来处理这个东西

\(A[i][j]\)表示从\(i\)出发,走了\(2^j\)轮时\(A\)开车的距离,\(B[i][j]\)同理

\(f[i][j]\)则表示\(2^j\)轮后的位置,倍增优化dp即可

Code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+11;
const int inf=3e9;
int n,m,ans,Aa,Ab,h[N],id[N],pre[N],nxt[N],p[N];
int f[N][20],A[N][20],B[N][20],mn[N],nmn[N];
inline bool cmp(int a,int b){return h[a]<h[b];}
int hdlt(int x,int y){return abs(h[x]-h[y]);}
void prepare(){
    h[0]=h[n+1]=inf;
    for(int i=1;i<n;i++){
        int v=p[i];
        mn[i]=nxt[v];nmn[i]=pre[v];
        if(hdlt(i,id[nmn[i]])<hdlt(i,id[mn[i]])) swap(mn[i],nmn[i]);
        int nt=nxt[nxt[v]],pe=pre[pre[v]];
        if(hdlt(i,id[nmn[i]])>hdlt(i,id[nt])) nmn[i]=nt;
        if(hdlt(i,id[nmn[i]])>hdlt(i,id[pe])) nmn[i]=pe;
        if(hdlt(i,id[nmn[i]])==hdlt(i,id[nt])&&h[id[nt]]<h[id[nmn[i]]]) nmn[i]=nt;
        if(hdlt(i,id[nmn[i]])==hdlt(i,id[pe])&&h[id[pe]]<h[id[nmn[i]]]) nmn[i]=pe;
        nmn[i]=id[nmn[i]];mn[i]=id[mn[i]];
        if(hdlt(i,nmn[i])==hdlt(i,mn[i])&&h[nmn[i]]<h[mn[i]]) swap(mn[i],nmn[i]);
        nxt[pre[v]]=nxt[v];pre[nxt[v]]=pre[v];
    }
    for(int i=1;i<n;i++){
        f[i][0]=mn[nmn[i]];
        A[i][0]=hdlt(i,nmn[i]);
        B[i][0]=hdlt(nmn[i],mn[nmn[i]]);
    }
}
void trans(){
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            A[i][j]=A[i][j-1]+A[f[i][j-1]][j-1];
            B[i][j]=B[i][j-1]+B[f[i][j-1]][j-1];
        }
}
void calc(int &a,int &b,int limit,int x){
    a=0,b=0;
    for(int i=19;i>=0;i--)
        if(f[x][i]&&A[x][i]+B[x][i]<=limit){
            a+=A[x][i],b+=B[x][i];
            limit-=A[x][i]+B[x][i];
            x=f[x][i];
        }
    if(hdlt(nmn[x],x)<=limit) a+=hdlt(nmn[x],x);
}
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
signed main(){
    n=read();
    for(int i=1;i<=n;i++)
        h[i]=read(),id[i]=i;
    sort(id+1,id+n+1,cmp);
    for(int i=1;i<=n;i++)
        pre[i]=i-1,nxt[i]=i+1,p[id[i]]=i;
    prepare();trans();
    int Limit=read();m=read();
    for(int i=1;i<=n;i++){
        int a,b;calc(a,b,Limit,i);
        if(!ans||a*Ab<Aa*b)
            Aa=a,Ab=b,ans=i;
    }
    printf("%lld\n",ans);
    for(int i=1;i<=m;i++){
        int x=read(),lim=read();
        int a,b;calc(a,b,lim,x);
        printf("%lld %lld\n",a,b);
    }
    return 0;
}
posted @ 2019-11-02 11:06  DQY_dqy  阅读(122)  评论(0编辑  收藏  举报