CodeForces - 675E

题意:一开始 你在第一个站 现在告诉每个站可以买一张票去其他地方(只能去比他坐标大的) 最后一个站没有卖


n表示 有n张车站


于是有n-1张车票


车票ai 表示这张车票可以从 i 车站出发 去 i+1 车站到 ai车站的任意一个车站 


现在 假设 pij 表示从i 到 j 的车站 最小用票数量


求所有的pij的和


思路:


假设我们在i车站 可以到  a b c 三个车站 而a b c必然可以到达其他的所有车站 (a < b <c )


其中 如果通过 a b c 再去其他站   我们选择肯定是a b c 中 能去最远的那个作为第二站


那么 假设b能去最远 我们通过 b 到达其他后面所有车站  且c是i一张票最远能去的车站 (b能去最远的距离必然大于c)


如果 我们通过一个车站 到达其他后面所有车站 那么相当于要每次多花一张票 除了 一张票就能到达的地方


那么 就需要 n-i + 中间站到其他所有站的票数 - c-b


故此就可以求出答案

#include <iostream>
#include <stdio.h>
using namespace std;
#define MAX 100010
#define LL long long

LL ans;
int dp[MAX*4];
LL a[MAX];
int rr[MAX];
int q,u;

void build(int l,int r,int tt)
{
    if(l==r)
    {
        dp[tt]=rr[l];
        return ;
    }
    int mid=(l+r)/2;
    build(mid+1,r,tt*2+1);
    build(l,mid,tt*2);
    dp[tt]=max(dp[tt*2],dp[tt*2+1]);
}

void query(int l,int r,int tt,int x,int y)
{
    if(x==l&&y==r)
    {
        if(dp[tt]>q)
        {
            q=dp[tt];
            while(l!=r)
            {
                int mid=(l+r)/2;
                if(dp[tt*2]==q){ r=mid;tt=tt*2;}
                else {l=mid+1; tt=tt*2+1;}
            }
            u=l;
        }
        return ;
    }

    int mid=(l+r)/2;
    if(mid<x)
        query(mid+1,r,tt*2+1,x,y);
    else if(y<=mid)
        query(l,mid,tt*2,x,y);
    else
    {
        query(l,mid,tt*2,x,mid);
        query(mid+1,r,tt*2+1,mid+1,y);
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d",&rr[i]);
    }
    rr[n]=n;
    build(1,n,1);
    for(int i=n-1;i>=1;i--)
    {
        q=0;
        query(1,n,1,i+1,rr[i]);
        a[i]=n-i+a[u]-(rr[i]-u);
        ans+=a[i];
    }
    printf("%lld\n",ans);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值