【开车旅行】

这是一道非常可怕的题

细节非常之多,就连\(INF\)设置的太小都会导致离奇错误

根据这道题一堆废话之后,我们首先要处理的是对于每个点,他下面那个要到达的点是谁

也就是距离他最近的点和次近的点分别是谁

看起来好像有些鬼,但是我们想一想这个距离是怎么定义的

“城市 \(i\) 和城市 $ j$之间的距离 \(d[i,j]\) 恰好是这两个城市海拔高度之差的绝对值,即$ d[i,j]=|h[i]-h[j]|$ 。”

最近的那个点显然就是前驱或者后继啊

那我们要是有一棵平衡树该多好啊

但是对于这种平衡树我们完全不用去手写,我们用\(set\)来代替就可以了

我们只需要\(s.find\)一下,之后左移右移一下迭代器就好了

之后对于次近的点

  1. 如果最近点是前驱,那么这个点肯定是后继或者是前驱的前驱

  2. 如果最近点是后继,那么这个点肯定是前驱或者是后继的后继

这里涉及到迭代器移动好几位,有可能越界

所以提前在\(set\)里插入一些\(INF\)\(-INF\)

这里的\(INF\)一定要足够大,否则就wa了

之后呢,我们看到对于每个点我们都需要往前开车,我们也可以暴力枚举一步一步的跳,但是这样的复杂度是\(O(n^2)\)

那有没有什么高效的跳的方法呢

那就是倍增

由于这里跳两次\(2^{j-1}\)步可以合并成跳\(2^j\)步,于是我们可以倍增

我们设\(f[i][j][opt]\)表示从\(i\)这个点由\(opt\)(0或1)跳\(2^j\)步能到达的点是谁

其中1代表A先走,0代表B先走

于是我们还需要一个数组来记录这样跳一共走了多少的距离

于是又有\(dp[i][j][opt]\)表示从\(i\)这个点由\(opt\)(0或1)跳\(2^j\)步走的距离是多少

我们还需要统计答案啊

我们需要知道A和B分别走了多少

于是又有\(d[i][j]\)表示从\(i\)这个点由A跳\(2^j\)步A走的距离是多少

至于这几个倍增数组怎么预处理

那写过树上倍增LCA的人应该都会的

至于怎么跳,其实就跟树上的倍增一样,我们从大里往小枚举这一步跳还是不跳就行了

于是代码

#include<set>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#define re register
#define mp make_pair
#define maxn 100001
#define LL long long
#define INF 990854775807
using namespace std;
typedef pair<int,int> pii;
multiset<pii> s;
int h[maxn],ans;
int t1[maxn],t2[maxn];
int ss[maxn],xx[maxn];
int f[maxn][18][2];
LL ansa[maxn],ansb[maxn];
LL dp[maxn][18][2],d[maxn][18];
int x0;
int n,m,H;
pii mid1,mid2,mid3;
multiset<pii>::iterator it;
LL aa=INF,bb=1;
inline int read()
{
    char c=getchar();
    int x=0,r=1;
    while(c<'0'||c>'9') 
    {
        if(c=='-') r=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') 
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x*r;
}
inline void jump(int sq,LL now,int t)
{
    ansa[t]=0;
    ansb[t]=0;
    for(re int i=H;i>=0;i--)
    if(f[sq][i][1]&&now-dp[sq][i][1]>=0)
    {
        now-=dp[sq][i][1];
        ansa[t]+=d[sq][i];
        ansb[t]+=dp[sq][i][1]-d[sq][i];
        sq=f[sq][i][1];
    }
}
inline LL gcd(LL a,LL b)
{
    if(!b) return a;
    return gcd(b,a%b);
}
inline void check(int x)
{
    if(!ansb[0]) ansa[0]=INF,ansb[0]=1;
    if(ansa[0]==INF) 
    {
        if(aa/bb==INF&&h[ans]<h[x]) ans=x,aa=1,bb=1;
        return;
    }
    LL r=gcd(ansa[0],ansb[0]);
    ansa[0]/=r,ansb[0]/=r;
    if(ansb[0]==bb&&ansa[0]==aa) 
    {
        if(h[ans]<h[x]) ans=x;
        return;
    }
    if(double(ansa[0])/double(ansb[0])<double(aa)/double(bb)) ans=x,aa=ansa[0],bb=ansb[0];
}
int main()
{
    n=read();
    H=log2(n);
    for(re int i=1;i<=n;i++)
        h[i]=read();
    t1[n-1]=n;
    dp[n-1][0][0]=abs(h[n]-h[n-1]);
    s.insert(mp(h[n],n));
    s.insert(mp(h[n-1],n-1));
    s.insert(mp(INF,0));
    s.insert(mp(-INF,0));
    s.insert(mp(INF,0));
    s.insert(mp(-INF,0));
    for(re int i=n-2;i;i--)
    {
        s.insert(mp(h[i],i));
        it=s.find(mp(h[i],i));
        it--;it--;
        if(s.begin()==it) 
        {
            it++,it++,it++;
            mid1=*it;
            t1[i]=mid1.second;
            dp[i][0][0]=mid1.first-h[i];
            it++;
            mid2=*it;
            t2[i]=mid2.second;
            dp[i][0][1]=d[i][0]=mid2.first-h[i];
        }
        else
        {
           	it++,it++;
            it++;
            mid1=*it;
            it--;it--;
            mid2=*it;
            if(h[i]-mid2.first<=mid1.first-h[i]) t1[i]=mid2.second;
            else t1[i]=mid1.second;
            if(t1[i]==mid2.second) 
            {
                it--;
                mid2=*it;
            }else it++,it++,it++,mid1=*it;
            LL a1=abs(mid1.first-h[i]),a2=abs(mid2.first-h[i]);
            if(a2<=a1) t2[i]=mid2.second;
            else t2[i]=mid1.second;
            dp[i][0][0]=abs(h[t1[i]]-h[i]);
            dp[i][0][1]=d[i][0]=abs(h[t2[i]]-h[i]);
        }
    }
    x0=read();
    m=read();
    for(re int i=1;i<=m;i++)
        ss[i]=read(),xx[i]=read();
    for(re int i=1;i<=n;i++)
        f[i][0][0]=t1[i],f[i][0][1]=t2[i];
    for(re int i=1;i<=n;i++)
    for(re int opt=0;opt<=1;opt++)
    {
        f[i][1][opt]=f[f[i][0][opt]][0][opt^1];
        dp[i][1][opt]=dp[i][0][opt]+dp[f[i][0][opt]][0][opt^1];
        if(opt) d[i][1]=d[i][0];
    }
    for(re int i=2;i<=H;i++)
    for(re int j=1;j<=n;j++)
    for(re int opt=0;opt<=1;opt++)
    {
        f[j][i][opt]=f[f[j][i-1][opt]][i-1][opt];
        dp[j][i][opt]=dp[j][i-1][opt]+dp[f[j][i-1][opt]][i-1][opt];
        if(opt) d[j][i]=d[j][i-1]+d[f[j][i-1][1]][i-1];
    }
    ans=1;
    jump(1,x0,0);
    aa=ansa[0];
    bb=ansb[0];
    if(!bb) aa=INF,bb=1;
    LL r=gcd(aa,bb);
    aa/=r;bb/=r;
    for(re int i=2;i<=n;i++)
        jump(i,x0,0),check(i);
    for(re int i=1;i<=m;i++)
        jump(ss[i],xx[i],i);
    cout<<ans<<endl;
    for(re int i=1;i<=m;i++)
        printf("%lld %lld",ansa[i],ansb[i]),putchar(10);
    return 0;
}
posted @ 2019-01-02 12:04  asuldb  阅读(155)  评论(0编辑  收藏  举报