Codeforces 675E Trains and Statistic - 线段树 - 动态规划
题目传送门
快速的vjudge通道
快速的Codeforces通道
题目大意
有$n$个火车站,第$i$个火车站出售第$i + 1$到第$a_{i}$个火车站的车票,特殊地,第$n$个火车站不出售车票。
记$\rho_{i, j}$表示从第$i$个火车站出发,到第$j$个火车站最少要购买的车票数。
求$\sum_{i = 1}^{n - 1}\sum_{j=i + 1}^{n}\rho_{i,j}$。
对于在$[i + 1, a_{i}]$中的火车站,肯定直接购买一张从$i$出发的火车票,然后就可以到达了。
对于这个区间之外的呢?那么我们一定会贪心地选择先到达一个火车站$p$,$p$满足$i < p \leqslant a_{i}, a_{p} \geqslant a_{k}( i < k \leqslant a_{i})$。
考虑在$a_{i}$之后的某个火车站$k$,如果我们想要到达它,经过的路线就是$i \rightarrow p \rightarrow \cdots \rightarrow k$.
因此$\rho_{i, k} = \rho_{p, k} + 1\ \ \ (k > a_{i})$。
令$f[i] = \sum_{j = i+1}^{n}\rho_{i, j}$,那么转移的时候区间加一,然后减去多算的一段。
找$p$可以用线段树。
Code
1 /** 2 * Codeforces 3 * Problem#675E 4 * Accepted 5 * Time: 61ms 6 * Memory: 7896k 7 */ 8 #include <bits/stdc++.h> 9 #ifndef WIN32 10 #define Auto "%lld" 11 #else 12 #define Auto "%I64d" 13 #endif 14 using namespace std; 15 typedef bool boolean; 16 17 #define pii pair<int, int> 18 #define fi first 19 #define sc second 20 #define ll long long 21 22 typedef class SegTreeNode { 23 public: 24 pii val; 25 SegTreeNode *l, *r; 26 27 SegTreeNode():l(NULL), r(NULL) { } 28 29 void pushUp() { 30 val = max(l->val, r->val); 31 } 32 }SegTreeNode; 33 34 SegTreeNode pool[300000]; 35 SegTreeNode *top = pool; 36 37 SegTreeNode* newnode() { 38 return top++; 39 } 40 41 typedef class SegTree { 42 public: 43 SegTreeNode *rt; 44 45 void build(SegTreeNode*& p, int l, int r, int* ar) { 46 p = newnode(); 47 if (l == r) { 48 p->val = pii(ar[l], l); 49 return ; 50 } 51 int mid = (l + r) >> 1; 52 build(p->l, l, mid, ar); 53 build(p->r, mid + 1, r, ar); 54 p->pushUp(); 55 } 56 57 pii query(SegTreeNode* p, int l, int r, int ql, int qr) { 58 if (ql == l && r == qr) 59 return p->val; 60 int mid = (l + r) >> 1; 61 if (qr <= mid) 62 return query(p->l, l, mid, ql, qr); 63 else if (ql > mid) 64 return query(p->r, mid + 1, r, ql, qr); 65 pii a = query(p->l, l, mid, ql, mid), b = query(p->r, mid + 1, r, mid + 1, qr); 66 return max(a, b); 67 } 68 }SegTree; 69 70 int n; 71 int *ar; 72 ll *f; 73 ll res = 0; 74 SegTree st; 75 76 inline void init() { 77 scanf("%d", &n); 78 ar = new int[(n + 1)]; 79 f = new ll[(n + 1)]; 80 for (int i = 1; i < n; i++) 81 scanf("%d", ar + i); 82 } 83 84 inline void solve() { 85 st.build(st.rt, 1, n, ar); 86 f[n] = 0; 87 for (int i = n - 1, j; i; i--) { 88 j = st.query(st.rt, 1, n, i + 1, ar[i]).sc; 89 f[i] = f[j] + n - i - (ar[i] - j); 90 res += f[i]; 91 } 92 printf(Auto"\n", res); 93 } 94 95 int main() { 96 init(); 97 solve(); 98 return 0; 99 }