Codeforces Round #353 (Div. 2) E. Trains and Statistic (线段树 + dp)
题目链接:http://codeforces.com/contest/675/problem/E
你可以从第 i 个车站到 [i + 1, a[i]] 之间的车站花一张票。
p[i][j]表示从 i 到 j 最少花费多少张票,问你 ∑p[i][j] (1<=i<j<=n) 是多少。
设dp[i]表示 i 到 [i+1, n] 总共花费的票。
已知 i 到 [i + 1, a[i]] 只要一张票就可以了。那么要是求i 到 大于a[i]的车站要多少票呢,这肯定需要一个[i + 1, a[i]] 最优的车站作为转移车站,那最优的肯定是a[temp]值最大的。
那么a[i] = a[temp] + (n - i) - (a[i] - temp) , temp表示[i+1 , a[i]]中a[j]最大的下标。
求区间最大线段树就行了,具体看代码。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef __int64 LL; 4 typedef pair <int , int> P; //first表示a[i]大小, second表示下标 5 const int MAXN = 1e5 + 5; 6 struct segtree { 7 int l , r , val , pos; 8 }T[MAXN << 2]; 9 int a[MAXN]; 10 LL dp[MAXN]; 11 12 void build(int p , int l , int r) { 13 int mid = (l + r) >> 1; 14 T[p].l = l , T[p].r = r; 15 if(l == r) { 16 T[p].val = a[l]; 17 T[p].pos = l; 18 return ; 19 } 20 build(p << 1 , l , mid); 21 build((p << 1)|1 , mid + 1 , r); 22 if(T[p << 1].val >= T[(p << 1)|1].val) { 23 T[p].val = T[p << 1].val; 24 T[p].pos = T[p << 1].pos; 25 } 26 else { 27 T[p].val = T[(p << 1)|1].val; 28 T[p].pos = T[(p << 1)|1].pos; 29 } 30 } 31 32 P query(int p , int l , int r) { 33 int mid = (T[p].l + T[p].r) >> 1; 34 if(T[p].l == l && T[p].r == r) { 35 return make_pair(T[p].val , T[p].pos); 36 } 37 if(r <= mid) { 38 return query(p << 1 , l , r); 39 } 40 else if(l > mid) { 41 return query((p << 1)|1 , l , r); 42 } 43 else { 44 P tmp1 = query(p << 1 , l , mid) , tmp2 = query((p << 1)|1 , mid + 1 , r); 45 return tmp1.first > tmp2.first ? tmp1 : tmp2; 46 } 47 } 48 49 int main() 50 { 51 int n; 52 scanf("%d" , &n); 53 for(int i = 1 ; i <= n - 1 ; ++i) { 54 scanf("%d" , a + i); 55 } 56 a[n] = n; 57 build(1 , 1 , n); 58 LL res = 0; 59 for(int i = n - 1 ; i >= 1 ; --i) { 60 int Max_pos = query(1 , i + 1 , a[i]).second; 61 dp[i] = dp[Max_pos] + (n - i) - (a[i] - Max_pos); 62 res += dp[i]; 63 } 64 printf("%lld\n" , res); 65 return 0; 66 }