分析
dp[ i ] 表示i的所有贡献
贪心的思想 假设i->j 我们每次都会选择 那个能到达的最远的那个k
这样我们可以保证我们少走至少一次
所以我们倒着推
#include <bits/stdc++.h>
using namespace std;
#define int long long
//typedef long long ll;
typedef pair<int,int> pii;
#define x first
#define y second
#define pb push_back
#define inf 1e18
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fer(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
const int maxn=1e5+10;
const int mod=1e9+7;
/*ll qsm(int a,int b)
{ll res=1; while(b){ if(b&1) res=res*a%mod; a=a*a%mod; b>>=1; } return res;}
*/
const int N=1e5+10;
int dr[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int n;
int a[N];
int dp[N];
struct node
{
int l,r;
pii val;
}tr[N*4];
void push_up(int i)
{
tr[i].val=max(tr[i*2].val,tr[i*2+1].val);
}
void build(int i,int l,int r)
{
tr[i].l=l,tr[i].r=r;
if(l==r)
{
tr[i].val={0,0};
return ;
}
int mid=(l+r)>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
}
void change(int i,int x,int val)
{
if(tr[i].l==tr[i].r)
{
tr[i].val={val,tr[i].l };
return ;
}
int mid=(tr[i].l+tr[i].r)>>1;
if(x<=mid) change(i*2,x,val);
else change(i*2+1,x,val);
push_up(i);
}
pii query(int i,int l,int r)
{
if(l<=tr[i].l&&r>=tr[i].r)
{
return tr[i].val;
}
int mid=(tr[i].l+tr[i].r)>>1;
pii tmp={0,0};
if(l<=mid) tmp=max(tmp,query(i*2,l,r));
if(r>mid) tmp=max(tmp,query(i*2+1,l,r));
return tmp;
}
void solve()
{
cin>>n;
fer(i,1,n-1)cin>>a[i];
a[n]=n;
build(1,1,n);
fer(i,1,n)change(1,i,a[i]);
// cout<<"***"<<endl;
int res=0;
for(int i=n-1,id;i>0;i--)
{
id=query(1,i+1,a[i]).y;
dp[i]=dp[id]-(a[i]-id)+n-i;
res+=dp[i];
}
cout<<res<<endl;
}
signed main()
{
IOS;
int _=1;
//cin>>_;
while(_--) solve();
return 0;
}