题意:一开始 你在第一个站 现在告诉每个站可以买一张票去其他地方(只能去比他坐标大的) 最后一个站没有卖
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;
}