• 【开车旅行】


    这是一道非常可怕的题

    细节非常之多,就连(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;
    }
    
  • 相关阅读:
    vue官方实例-组件
    数据处理-js
    图片大于div时的居中显示
    angularjs select通过动态加载option有空白项的处理方法-
    背景图片自适应div
    input-text
    input-number-required
    input-number-not-required
    null与undefined的区别?
    是true还是false呢?
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207826.html
Copyright © 2020-2023  润新知