zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
  • 相关阅读:
    HashMap按键排序和按值排序
    LeetCode 91. Decode Ways
    LeetCode 459. Repeated Substring Pattern
    JVM
    LeetCode 385. Mini Parse
    LeetCode 319. Bulb Switcher
    LeetCode 343. Integer Break
    LeetCode 397. Integer Replacement
    LeetCode 3. Longest Substring Without Repeating Characters
    linux-网络数据包抓取-tcpdump
  • 原文地址:https://www.cnblogs.com/Narh/p/9382336.html
Copyright © 2011-2022 走看看