CF1601 B. Frog Traveler

Problem - 1601B - Codeforces

 

题意:

井下深度为n,在井下深度为i的地方可以往上跳[0,ai]米

如果没有跳出井,则要下滑bi米

问最少跳几次可以跳出井

 

假设跳[1,d]可以出井的位置都求出来了

现在求跳d+1次可以出井的位置

枚举跳d次可以出井的位置v,若从位置u可以滑倒位置v,即u+b[u]=v,

那么对于一个没有算过的位置j,如果他能跳到位置u,那么从位置j就是跳d+1次出井

即 j-a[j]<=u<=j

可以采用队列以此计算d=1,2.3……

每次取队首作为v

u可以提前预处理

求位置j可以用线段树,把j-a[j]放到第j个叶子节点,求区间最小值

 

#include<bits/stdc++.h>
 
using namespace std;
 
#define N 300004
 
int a[N],b[N],f[N];
int tr[N<<2],w[N<<2];

queue<int>q;
vector<int>v[N];

int pos,mi;

int front[N],to[N];

void build(int k,int l,int r)
{
    if(l==r)
    {
        tr[k]=l-a[l];
        w[k]=l;
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    if(tr[k<<1]<=tr[k<<1|1])
    {
        tr[k]=tr[k<<1];
        w[k]=w[k<<1];
    }
    else
    {
        tr[k]=tr[k<<1|1];
        w[k]=w[k<<1|1]; 
    }
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        if(tr[k]<mi)
        {
            mi=tr[k];
            pos=w[k];
        }
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr); 
}

void change(int k,int l,int r,int p)
{
    if(l==r)
    {
        tr[k]=1e9;
        return;
    }
    int mid=l+r>>1;
    if(p<=mid) change(k<<1,l,mid,p);
    else change(k<<1|1,mid+1,r,p);
    if(tr[k<<1]<=tr[k<<1|1])
    {
        tr[k]=tr[k<<1];
        w[k]=w[k<<1];
    }
    else
    {
        tr[k]=tr[k<<1|1];
        w[k]=w[k<<1|1]; 
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    for(int i=1;i<=n;++i) 
    {
        scanf("%d",&b[i]);
        v[i+b[i]].push_back(i);
    }
    v[0].push_back(0); 
    build(1,0,n);
    f[0]=0;
    q.push(0);
    change(1,0,n,0);
    int now,st;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=0;i<v[now].size();++i)
        {
            st=v[now][i];
            while(1)
            {
                pos=-1;
                mi=1e9;
                query(1,0,n,st,n);
                if(mi>v[now][i]) break;
                f[pos]=f[now]+1;
                q.push(pos);
                change(1,0,n,pos);
                front[pos]=now;
                to[pos]=st;
            }
        }
    }
    if(!f[n])
    {
        printf("-1");
        return 0;
    }
    printf("%d\n",f[n]); 
    now=n;
    while(now)
    {
        printf("%d ",to[now]);
        if(!to[now]) break;
        now=front[now];
    }
}

 

posted @ 2021-11-06 11:18  TRTTG  阅读(147)  评论(0编辑  收藏  举报