题目传送门
题目大意
给定一个长度为$n$的序列。询问区间$[l, r]$的所有不同的子序列的最小值的和。
这里的子序列是连续的。两个子序列不同当且仅当它们的左端点或右端点不同。
不会直接上神奇数据结构的做法。
考虑莫队。当在一段右边加入一个数后,考虑它产生的贡献。
首先找到加入后这一段的最小值,那么左端点在它的左侧的时候这个最小值做出贡献。
对于它右边到新加入的数新造成的贡献用同样的方法计算,期望下多带个$log$,然后题目没说数据随机。
考虑右边这一部分其实被算重了许多次,因为最小值右边的分段情况比较固定。因为每个"最小值"有一个固定的“恶势力”范围。这个东西可以用前缀和再加上单调栈预处理。
求最小的任务就交给st表好了。
Code
1 /** 2 * bzoj 3 * Problem#4540 4 * Accepted 5 * Time: 10024ms 6 * Memory: 34932k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #ifndef WIN32 13 #define Auto "%lld" 14 #else 15 #define Auto "%I64d" 16 #endif 17 using namespace std; 18 typedef bool boolean; 19 20 const signed int inf = (signed) (~0u >> 1); 21 const int N = 1e5 + 5, bzmax = 18; 22 #define pii pair<int, int> 23 #define fi first 24 #define sc second 25 26 typedef class SparseTable { 27 public: 28 int n; 29 int *ar; 30 int log2[N]; 31 pii bz[N][bzmax]; 32 33 SparseTable() { } 34 SparseTable(int n, int* ar):n(n) { 35 log2[1] = 0; 36 for (int i = 2; i <= n; i++) 37 log2[i] = log2[i >> 1] + 1; 38 for (int i = 1; i < n; i++) 39 bz[i][0] = min(pii(ar[i], i), pii(ar[i + 1], i + 1)); 40 for (int j = 1; j < bzmax; j++) 41 for (int i = 1; i + (1 << j) <= n + 1; i++) 42 bz[i][j] = min(bz[i][j - 1], bz[i + (1 << (j - 1))][j - 1]); 43 } 44 45 int query(int l, int r) { 46 if (l == r) return l; 47 int l2 = log2[r - l]; 48 return min(bz[l][l2], bz[r - (1 << l2)][l2]).sc; 49 } 50 }SparseTable; 51 52 const int cs = 350; 53 #define ll long long 54 55 typedef class Query { 56 public: 57 int l, r, id; 58 ll res; 59 60 Query() { } 61 62 boolean operator < (Query b) const { 63 if (l / cs != b.l / cs) return l / cs < b.l / cs; 64 return r < b.r; 65 } 66 }Query; 67 68 int n, m; 69 int tp = -1; 70 Query *qs; 71 SparseTable st; 72 ll *pl, *pr; 73 int *ar; 74 pii *sta; 75 76 inline void init() { 77 scanf("%d%d", &n, &m); 78 pl = new ll[(n + 1)]; 79 pr = new ll[(n + 2)]; 80 ar = new int[(n + 1)]; 81 sta = new pii[(n + 1)]; 82 qs = new Query[(m + 1)]; 83 for (int i = 1; i <= n; i++) 84 scanf("%d", ar + i); 85 st = SparseTable(n, ar); 86 for (int i = 1; i <= m; i++) 87 scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i; 88 } 89 90 inline void prepare() { 91 sta[++tp] = pii(0, -inf); 92 pl[0] = 0, pr[n + 1] = 0; 93 for (int i = 1; i <= n; i++) { 94 while (tp && sta[tp].sc >= ar[i]) 95 tp--; 96 pl[i] = pl[sta[tp].fi] + (i - sta[tp].fi) * 1ll * ar[i]; 97 sta[++tp] = pii(i, ar[i]); 98 } 99 100 sta[tp = 0] = pii(n + 1, -inf); 101 for (int i = n; i; i--) { 102 while (tp && sta[tp].sc >= ar[i]) 103 tp--; 104 pr[i] = pr[sta[tp].fi] + (sta[tp].fi - i) * 1ll * ar[i]; 105 sta[++tp] = pii(i, ar[i]); 106 } 107 } 108 109 ll res = 0; 110 111 inline void solve() { 112 sort(qs + 1, qs + m + 1); 113 int c = 1; 114 for (int sid = 0, p; sid <= n / cs && c <= m; sid++) { 115 int mdzzl = 1, mdzzr = 0; 116 res = 0; 117 for ( ; c <= m && qs[c].l / cs == sid; c++) { 118 while (mdzzr < qs[c].r) { 119 p = st.query(mdzzl, ++mdzzr); 120 res += (p - mdzzl + 1) * 1ll * ar[p] + pl[mdzzr] - pl[p]; 121 } 122 while (mdzzl < qs[c].l) { 123 p = st.query(mdzzl, mdzzr); 124 res -= (mdzzr - p + 1) * 1ll * ar[p] + pr[mdzzl] - pr[p]; 125 mdzzl++; 126 } 127 while (mdzzl > qs[c].l) { 128 p = st.query(--mdzzl, mdzzr); 129 res += (mdzzr - p + 1) * 1ll * ar[p] + pr[mdzzl] - pr[p]; 130 } 131 qs[c].res = res; 132 } 133 } 134 for (int i = 1; i <= m; i++) 135 while (qs[i].id != i) 136 swap(qs[i], qs[qs[i].id]); 137 for (int i = 1; i <= m; i++) 138 printf(Auto"\n", qs[i].res); 139 } 140 141 int main() { 142 init(); 143 prepare(); 144 solve(); 145 return 0; 146 }