洛谷1081 (NOIp2012) 开车旅行——倍增预处理

题目:https://www.luogu.org/problemnew/show/P1081

预处理从每个点开始a能走多少、b能走多少。可以像dp一样从后往前推。

但有X的限制。所以该数组可以变成倍增的样子。

预处理第一步的找下一个点可以从后往前弄,在树状数组上二分。然后正常转移即可。

树状数组上的二分有细节:

  找第一个 f 值为需要的值k的,可以if( query( mid )>=k )ans=mid,r=mid-1;也可以if( query(mid)<=k-1 )ans=mid,l=mid+1; ans++;

倍增数组也有细节,大约就是当目的地为0的时候就不要给距离赋值了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e5+5;
const double eps=1e-10,INF=2e9+5;
int n,m,h[N],tp[N],f[N],ps[N],S;
ll X,dp[N][20][3],mp[N],s[N],ca,cb;
double tc=INF;
int rdn()
{
    int ret=0,fx=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')fx=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret*fx;
}
ll rdl()
{
    ll ret=0,fx=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')fx=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret*fx;
}
void add(int x,int k){for(;x<=m;x+=(x&-x))f[x]+=k;}
int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;}
void find(int i,int &ps0,int &ps1)
{
    ps0=0;ps1=0;
    int k=query(h[i]),l=1,r=m,tp0=0,tp1=0,antp=0;
//    printf("i=%d k=%d
",i,k);
    if(n-i+1>k)
    {
        while(l<=r)
        {
            int mid=l+r>>1;
            if(query(mid)<=k)tp0=mid,l=mid+1;
            else r=mid-1;
        }
        tp0++;
    }
    if(k>1)
    {
        l=1;r=m;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(query(mid)>=k-1)tp1=mid,r=mid-1;
            else l=mid+1;
        }
    }
    if(!tp0&&tp1)ps0=ps[tp1],antp=tp1;else if(tp0&&!tp1)ps0=ps[tp0],antp=tp0;
    else if(tp0&&tp1)
        {if(tp[h[i]]-tp[tp1]>tp[tp0]-tp[h[i]])ps0=ps[tp0],antp=tp0;else ps0=ps[tp1],antp=tp1;}
//    printf("tp0=%d tp1=%d ps0=%d
",tp0,tp1,ps0);
    if(antp)add(antp,-1);
    k=query(h[i]);tp0=tp1=0;
//    printf("i=%d k=%d(antp=%d)
",i,k,antp);
    if(n-i>k)
    {
        l=1;r=m;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(query(mid)<=k)tp0=mid,l=mid+1;
            else r=mid-1;
        }
        tp0++;
    }
    if(k>1)
    {
        l=1;r=m;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(query(mid)>=k-1)tp1=mid,r=mid-1;
            else l=mid+1;
        }
    }
    if(!tp0&&tp1)ps1=ps[tp1];else if(tp0&&!tp1)ps1=ps[tp0];
    else if(tp0&&tp1){if(tp[h[i]]-tp[tp1]>tp[tp0]-tp[h[i]])ps1=ps[tp0];else ps1=ps[tp1];}
//    printf("tp0=%d tp1=%d ps1=%d
",tp0,tp1,ps1);
    if(antp)add(antp,1);
}
void cz(int cr)
{
    int a,b;find(cr,b,a);
    dp[cr][0][2]=a;mp[cr]=b;
    if(a)dp[cr][0][0]=abs(tp[h[a]]-tp[h[cr]]);
    
    int ta=mp[a];
    if(ta)
    {
        dp[cr][1][2]=ta;
        dp[cr][1][0]=dp[cr][0][0];  if(ta)dp[cr][1][1]=abs(tp[h[ta]]-tp[h[a]]);
    }
//    printf("cr=%d a=%lld b=%lld(a=%d ta=%d)
",cr,dp[cr][1][0],dp[cr][1][1],a,ta);
    
    for(int i=2;i<=17;i++)
    {
        a=dp[cr][i-1][2];if(!dp[a][i-1][2])break;//
        dp[cr][i][0]=dp[cr][i-1][0]+dp[a][i-1][0];
        dp[cr][i][1]=dp[cr][i-1][1]+dp[a][i-1][1];
        dp[cr][i][2]=dp[a][i-1][2];
    }
}
int main()
{
    n=rdn();
    for(int i=1;i<=n;i++)tp[i]=h[i]=rdn();
    sort(tp+1,tp+n+1);m=unique(tp+1,tp+n+1)-tp-1;
    for(int i=n;i;i--)
    {
        h[i]=lower_bound(tp+1,tp+n+1,h[i])-tp;
        add(h[i],1);ps[h[i]]=i;cz(i);
    }
    X=rdl();ll yX=X;
    for(int i=1;i<=n;i++)
    {
//        printf("i=%d
",i);
        int now=i;ca=0;cb=0;X=yX;
        for(int j=17;j;j--)
//        {
//            if(j<=3)printf("X=%lld now=%d j=%d a=%lld b=%lld
"
//                ,X,now,j,dp[now][j][0],dp[now][j][1]);
            if(dp[now][j][0]+dp[now][j][1]<=X)
            {
                X-=dp[now][j][0]+dp[now][j][1];
                ca+=dp[now][j][0];cb+=dp[now][j][1];
                if(dp[now][j][2])now=dp[now][j][2];
            }
//        }
//        printf("X=%lld now=%d j=0 a=%lld
",X,now,dp[now][0][0]);
        if(now&&dp[now][0][0]<=X)ca+=dp[now][0][0];
//        printf("i=%d ca=%lld cb=%lld
",i,ca,cb);
        if(cb)
        {
            double w=(double)ca/cb;
            if(w<tc||(fabs(w-tc)<=eps&&h[i]>h[S]))tc=w,S=i;
        }
//        printf("i=%d S=%d
",i,S);
    }
    printf("%d
",S);
    m=rdn();
    while(m--)
    {
        S=rdn();X=rdn();
        int now=S;ca=0;cb=0;
        for(int j=17;j;j--)
//        {
//            if(j<=3)printf("X=%lld now=%d j=%d a=%lld b=%lld
"
//                ,X,now,j,dp[now][j][0],dp[now][j][1]);
            if(dp[now][j][0]+dp[now][j][1]<=X)
            {
                X-=dp[now][j][0]+dp[now][j][1];
                ca+=dp[now][j][0];cb+=dp[now][j][1];
                if(dp[now][j][2])now=dp[now][j][2];
            }
//        }
//        printf("X=%lld now=%d j=0 a=%lld
",X,now,dp[now][0][0]);
        if(now&&dp[now][0][0]<=X)ca+=dp[now][0][0];
        printf("%lld %lld
",ca,cb);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9382336.html