【CF675E】Trains and Statistic(贪心,DP,线段树优化)

【CF675E】Trains and Statistic(贪心,DP,线段树优化)

题意:
a[i]表示从第i个车站可以一张票到第[i+1,a[i]]这些车站;
p[i][j]表示从第i个车站到第j个车站的最少的票数,现在要求∑dp[i][j](1<=i<=n,i<j<=n);

思路:从I开始走,在i+1到a[i]之间一定会到使a[j]最大的j,因为要使步数最小,接下来能走得更快
区间询问最值用RMQ与线段树都可以
dp[i]表示dp[i,i+1],dp[i,i+2]...dp[i,n]这些值的和
dp[i]=dp[k]+(n-i)-(a[i]-k),k为[i+1,a[i]]中使a[k]最大的k
n-i:有dp[i,i+1],dp[i,i+2]...dp[i,n]一共n-i个状态要从i走到k
-(a[i]-k):dp[i,k+1]到 dp[i,a[i]]长度与之前相比没有变化
 1 type ok=record
 2          s:int64;
 3          a:longint;
 4         end;
 5 
 6 const oo=1000000000000000;
 7 
 8 var dp:array[0..100000]of int64;
 9     a:array[1..100000]of longint;
10     tree:array[1..400000]of ok;
11     n,i,k:longint;
12     ans:int64;
13 
14 procedure pushup(p:longint);
15 begin
16  if tree[p<<1].s>tree[p].s then tree[p]:=tree[p<<1];
17  if tree[p<<1+1].s>tree[p].s then tree[p]:=tree[p<<1+1];
18 end;
19 
20 procedure build(l,r,p:longint);
21 var mid:longint;
22 begin
23  tree[p].s:=a[l];
24  tree[p].a:=l;
25  if l=r then exit;
26  mid:=(l+r)>>1;
27  build(l,mid,p<<1);
28  build(mid+1,r,p<<1+1);
29  pushup(p);
30 end;
31 
32 function query(l,r,x,y,p:longint):ok;
33 var mid:longint;
34     t:int64;
35     q,tmp:ok;
36 
37 begin
38  if (l=x)and(r=y) then exit(tree[p]);
39  mid:=(l+r)>>1;
40  t:=0;
41  if (x>=l)and(y<=mid) then
42  begin
43   q:=query(l,mid,x,y,p<<1);
44   if q.s>t then begin t:=q.s; tmp:=q; end;
45  end else
46  if (x>mid)and(y<=r) then
47  begin
48   q:=query(mid+1,r,x,y,p<<1+1);
49   if q.s>t then begin t:=q.s; tmp:=q; end;
50  end else
51  begin
52   q:=query(l,mid,x,mid,p<<1);
53   if q.s>t then begin t:=q.s; tmp:=q; end;
54   q:=query(mid+1,r,mid+1,y,p<<1+1);
55   if q.s>t then begin t:=q.s; tmp:=q; end;
56  end;
57  exit(tmp);
58 end;
59 
60 begin
61  //assign(input,'1.in'); reset(input);
62  //assign(output,'1.out'); rewrite(output);
63  readln(n);
64  for i:=1 to n-1 do read(a[i]);
65  a[n]:=n;
66  build(1,n,1);
67 
68  for i:=n-1 downto 1 do
69  begin
70   k:=query(1,n,i+1,a[i],1).a;
71   dp[i]:=dp[k]+(n-i)-(a[i]-k);
72  end;
73  for i:=1 to n do ans:=ans+dp[i];
74  writeln(ans);
75  //close(input);
76  //close(output);
77 end.