vijos 1780 开车旅行

Posted ziliuziliu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vijos 1780 开车旅行相关的知识,希望对你有一定的参考价值。

细节巨多。

倍增即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
#include<cstdlib>
#define maxv 200500
#define maxn 100500
#define eps 1e-7
#define inf 0x7f7f7f7f7f7f7f7fLL
using namespace std;
long long n,m,h[maxn],x,y,aft[maxn][3],anc[maxv][20],dis1[maxv][20],dis2[maxv][20],hashed[maxn],pos[maxn];
long long ret1=0,ret2=0,ans;
struct pnt
{
    long long ret,dot,rets;
}p[5];
set <long long> s;
set <long long> ::iterator it;
double ans1=inf;
bool cmp(pnt x,pnt y)
{
    if (x.ret!=y.ret) return x.ret<y.ret;
    return x.rets>y.rets;
}
void divide()
{
    for (long long i=1;i<=n;i++) hashed[i]=h[i];
    sort(hashed+1,hashed+n+1);
    for (long long i=1;i<=n;i++)
    {
        h[i]=lower_bound(hashed+1,hashed+n+1,h[i])-hashed;
        pos[h[i]]=i;
    }
}
long long ask(long long x,long long y)
{
    ret1=0;ret2=0;
    for (long long e=19;e>=0;e--)
    {
        if ((ret1+ret2+dis1[x][e]+dis2[x][e]<=y) && (anc[x][e]))
        {
            ret1+=dis1[x][e];ret2+=dis2[x][e];
            x=anc[x][e];
        }
    }
}
void update(long long x)
{
    if (!ret1) return;
    if ((double)ret2/ret1<ans1) {ans1=(double)ret2/ret1;ans=x;}
    else if (((double)ret2/ret1-ans1<=eps) && (hashed[h[ans]]<hashed[h[x]])) ans=x;
}
int main()
{
    scanf("%lld",&n);
    for (long long i=1;i<=n;i++) scanf("%lld",&h[i]);
    divide();
    for (long long i=n;i>=1;i--)
    {
        for (long long j=1;j<=4;j++) p[j].dot=p[j].ret=inf;
        it=s.lower_bound(h[i]);
        if (it!=s.end())
        {
            p[3].ret=hashed[h[pos[*it]]];p[3].dot=pos[*it];
            if (++it!=s.end()) {p[4].ret=hashed[h[pos[*it]]];p[4].dot=pos[*it];}
            it--;
        }
        if (it!=s.begin())
        {
            it--;
            p[1].ret=hashed[h[pos[*it]]];p[1].dot=pos[*it];
            if (it!=s.begin()) {it--;p[2].ret=hashed[h[pos[*it]]];p[2].dot=pos[*it];it++;}
        }
        for (int j=1;j<=4;j++)
        {
            if (p[j].ret!=inf)
            {
                p[j].rets=hashed[h[i]]-p[j].ret;
                p[j].ret=abs(hashed[h[i]]-p[j].ret);
            }
        }
        sort(p+1,p+5,cmp);
        if (p[1].ret!=inf) aft[i][1]=p[1].dot;
        if (p[2].ret!=inf) aft[i][2]=p[2].dot;
        s.insert(h[i]);
    }
    for (long long i=1;i<=n;i++)
    {
        anc[2*i-1][0]=2*aft[i][1];dis1[2*i-1][0]=abs(hashed[h[aft[i][1]]]-hashed[h[i]]);dis2[2*i-1][0]=0;
        anc[2*i][0]=max(2*aft[i][2]-1,(long long)0);dis1[2*i][0]=0;dis2[2*i][0]=abs(hashed[h[aft[i][2]]]-hashed[h[i]]);
    }
    n*=2;
    for (long long e=1;e<=19;e++)
        for (long long i=1;i<=n;i++)
        {
            anc[i][e]=anc[anc[i][e-1]][e-1];
            dis1[i][e]=dis1[i][e-1]+dis1[anc[i][e-1]][e-1];
            dis2[i][e]=dis2[i][e-1]+dis2[anc[i][e-1]][e-1];
        }
    scanf("%lld",&x);
    for (long long i=2;i<=n;i+=2) 
        {ask(i,x);update(i/2);}
    printf("%d\n",ans);
    scanf("%lld",&m);
    for (long long i=1;i<=m;i++)
    {
        scanf("%lld%lld",&x,&y);
        ask(2*x,y);
        printf("%lld %lld\n",ret2,ret1);
    }
    return 0;
}

 

以上是关于vijos 1780 开车旅行的主要内容,如果未能解决你的问题,请参考以下文章

Vijos[1983]NOIP2015Day2T3 运输计划 transport LCA

开车旅行

Luogu1081 开车旅行

题解 P1081 开车旅行

NOIP2012开车旅行

codevs1199 开车旅行