zoukankan      html  css  js  c++  java
  • 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];
        }
    }
    作者:xxy
    本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
  • 相关阅读:
    返回数组指针的函数形式
    zoj 2676 网络流+01分数规划
    2013 南京理工大学邀请赛B题
    poj 2553 强连通分支与缩点
    poj 2186 强连通分支 和 spfa
    poj 3352 边连通分量
    poj 3177 边连通分量
    poj 2942 点的双连通分量
    poj 2492 并查集
    poj 1523 求割点
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/15516248.html
Copyright © 2011-2022 走看看