• codeforces 675E Trains and Statistic 线段树+贪心统计


    分析:这个题刚看起来无从下手

    但是我们可以先简化问题,首先可以固定起点i,求出i+1到n的最小距离

    它可以到达的范围是[i+1,a[i]],贪心的想,我们希望换一次车可以到达的距离尽量远

    即:找一个k,使得i+1<=k<=a[i],a[k]的值最大,就可以保证,换一次车,可以到达的距离最

    找k的操作可以用线段树来完成

    统计当前dp[i]=dp[k]+(n-i)-(a[i]-k),因为当前区间内的点在[k+1,a[i]]的点多计了一次,所以减去

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <stdlib.h>
    #include <map>
    #include <queue>
    #include <set>
    using namespace std;
    typedef long long LL;
    const int INF=0x3f3f3f3f;
    const int N=1e5+5;
    int c[N<<2],a[N];
    LL dp[N];
    void up(int rt){
      if(a[c[rt<<1]]>=a[c[rt<<1|1]])
        c[rt]=c[rt<<1];
      else c[rt]=c[rt<<1|1];
    }
    void build(int rt,int l,int r){
      if(l==r){c[rt]=l;return;}
      int m=(l+r)>>1;
      build(rt<<1,l,m);
      build(rt<<1|1,m+1,r);
      up(rt);
    }
    int ask(int rt,int l,int r,int x,int y){
      if(x<=l&&r<=y)return c[rt];
      int ls=-1,rs=-1,m=(l+r)>>1;
      if(x<=m)ls=ask(rt<<1,l,m,x,y);
      if(y>m)rs=ask(rt<<1|1,m+1,r,x,y);
      if(ls==-1)return rs;
      if(rs==-1)return ls;
      if(a[ls]>=a[rs])return ls;
      else return rs;
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<n;++i)
          scanf("%d",&a[i]);
        a[n]=n;
        LL ret=0;
        build(1,1,n);
        for(int i=n-1;i>0;--i){
           int pos=ask(1,1,n,i+1,a[i]);
           dp[i]=dp[pos]+(n-i)-(a[i]-pos);
           ret+=dp[i];
        }
        printf("%I64d
    ",ret);
        return 0;
    }
    View Code
  • 相关阅读:
    算法第五章作业
    第四章实验报告
    算法第三章作业
    算法第三章上机实验报告
    算法第二章作业
    算法第二章上机实践报告
    算法 代码规范(C++)&《数学之美》读后感
    第七章学习小结
    第六章学习小结
    第五章学习小结
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5535192.html
Copyright © 2020-2023  润新知