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 } 
posted @ 2018-03-09 20:25  阿波罗2003  阅读(188)  评论(0编辑  收藏  举报