【HNOI2016】序列
阿新 • • 發佈:2019-02-26
端點 main tdi ++ 復雜度 eof noi 全部 data ,右端點為\([x, r]\)的全部答案。
,那麽答案就是\(g_r - g_p - f_p \times (r - p)\)。
題面
題解
設\([l, r]\)的最小值的位置為\(p\),那麽對於左端點在區間\([l, p]\),右端點在區間\([p, r]\)的區間最小值都為\(a[p]\)。
這一部分的貢獻就是\(a[p] \times (p - l + 1) \times (r - p + 1)\)
設\(f_i = f_{\mathrm{pre}_i} + a_i \times (i - \mathrm{pre}_i)\),於是我們可以發現\(f_{r + 1} - f_p\)就是以\(r + 1\)為右端點,左端點為\([p + 1, r + 1]\)的答案。
但是我們這裏要考慮左端點為\((p, x]\)
對於點\(r\),所有以\(r\)為右端點,左端點在\((p, r]\)的答案為\(f_r - f_p\)。
對於點\(r - 1\),所有以\(r - 1\)為右端點,左端點在\((p, r - 1]\)的答案為\(f_{r - 1} - f_p\)
\(\cdots\)
對於點\(p + 1\),所有以\(p + 1\)為右端點,左端點在\((p, p + 1]\)的區間答案為\(f_{p + 1} - f_p\)
求個和,就是\((\sum_{i = p + 1} ^ r f_i) - f_p \times(r - p)\)。
設\(g_i = \sum_{j = 1} ^ i f_j\)
同樣\(p\)左邊的情況是類似的。
時間復雜度\(\mathrm{O}(n\log_2 n)\)
代碼
#include<cstdio> #include<cstring> #include<algorithm> #define RG register #define clear(x, y) memset(x, y, sizeof(x)) namespace IO { const int BUFSIZE = 1 << 20; char ibuf[BUFSIZE], *is = ibuf, *it = ibuf; inline char getchar() { if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); return *is++; } } inline int read() { int data = 0, w = 1; char ch = IO::getchar(); while(ch != '-' && (ch < '0' || ch > '9')) ch = IO::getchar(); if(ch == '-') w = -1, ch = IO::getchar(); while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::getchar(); return data * w; } const int maxn(1e5 + 10), INF(0x3f3f3f3f), LogN(17); int n, m, f[LogN][maxn], a[maxn], pre[maxn], suc[maxn]; long long fl[maxn], fr[maxn], gl[maxn], gr[maxn]; int Log[maxn], stk[maxn], top; inline int min(int x, int y) { return a[x] < a[y] ? x : y; } inline int query(int l, int r) { int k = Log[r - l + 1]; return min(f[k][l], f[k][r - (1 << k) + 1]); } int main() { n = read(), m = read(); a[0] = a[n + 1] = INF, Log[0] = -1; for(RG int i = 1; i <= n; i++) a[f[0][i] = i] = read(), Log[i] = Log[i >> 1] + 1; for(RG int i = 1; i <= Log[n]; i++) for(RG int j = 1; j <= n - (1 << (i - 1)) + 1; j++) f[i][j] = min(f[i - 1][j], f[i - 1][j + (1 << (i - 1))]); for(RG int i = 1; i <= n; i++) { while(top && a[stk[top]] > a[i]) suc[stk[top--]] = i; pre[i] = stk[top], stk[++top] = i; } while(top) pre[stk[top]] = stk[top - 1], suc[stk[top--]] = n + 1; for(RG int i = 1; i <= n; i++) fr[i] = 1ll * a[i] * (i - pre[i]) + fr[pre[i]], gr[i] = gr[i - 1] + fr[i]; for(RG int i = n; i; i--) fl[i] = 1ll * a[i] * (suc[i] - i) + fl[suc[i]], gl[i] = gl[i + 1] + fl[i]; while(m--) { int l = read(), r = read(), p = query(l, r); printf("%lld\n", 1ll * (p - l + 1) * (r - p + 1) * a[p] + gr[r] - gr[p] - fr[p] * (r - p) + gl[l] - gl[p] - fl[p] * (p - l)); } return 0; }
【HNOI2016】序列