BZOJ3956: Count
orz 出题人Gromah
这道题我的算法和他的标解完全不一样,目前在bzoj上是第一名,空间开销也是当前最小的(截个图纪念一下)
首先用单调栈$O(n)$地预处理出以每个点为左端点、右端点的可行点对个数。
然后对于每个询问$[l, r]$中,我们找到其中权值最大的点,假设它是$p$
然后可以发现一个性质,在$[l, r]$中的所有可行点对都不会穿过$p$,如果穿过的话因为$p$是权值最大的点所以不合法
于是我们只要统计$[l, p - 1]$的所有点作为左端点时的合法点对和$[p + 1, r]$的所有点作为右端点时的合法点对数量即可
用ST表维护区间最大值
时间复杂度$O(nlogn + m)$,空间复杂度$O(nlogn)$
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #include <map> 7 using namespace std; 8 #define rep(i, l, r) for (int i = l; i <= r; i++) 9 #define drep(i, r, l) for (int i = r; i >= l; i--) 10 typedef long long ll; 11 const int N = 3e5 + 8; 12 int n, m, ty, logn, st[22][N], L[N], R[N], son[N], a[N], top, q[N]; 13 ll sumL[N], sumR[N]; 14 int getint() 15 { 16 char c; int num = 0, w = 1; 17 for (c = getchar(); !isdigit(c) && c != '-'; c = getchar()); 18 if (c == '-') c = getchar(), w = -1; 19 for (;isdigit(c); c = getchar()) num = num * 10 + c - '0'; 20 return num * w; 21 } 22 void init() 23 { 24 logn = (int)(log(n) / log(2.0)); 25 rep(i, 1, n) 26 { 27 son[i] = son[i - 1]; 28 if ((1 << son[i] + 1) <= i) son[i]++; 29 } 30 rep(i, 1, n) st[0][i] = i; 31 rep(i, 1, logn) 32 rep(j, 1, n) 33 { 34 int x = st[i - 1][j], y = st[i - 1][j + (1 << i - 1)]; 35 if (a[x] > a[y]) st[i][j] = x; 36 else st[i][j] = y; 37 } 38 q[top = 1] = 1; 39 rep(i, 2, n) 40 { 41 while (top && a[i] > a[q[top]]) L[i]++, top--; 42 if (top) L[i]++; 43 while (top && a[i] >= a[q[top]]) top--; 44 q[++top] = i; 45 } 46 rep(i, 1, n) sumL[i] = sumL[i - 1] + L[i]; 47 q[top = 1] = n; 48 drep(i, n - 1, 1) 49 { 50 while (top && a[i] > a[q[top]]) R[i]++, top--; 51 if (top) R[i]++; 52 while (top && a[i] >= a[q[top]]) top--; 53 q[++top] = i; 54 } 55 rep(i, 1, n) sumR[i] = sumR[i - 1] + R[i]; 56 } 57 int query(int l, int r) 58 { 59 int k = son[r - l + 1]; 60 int x = st[k][l], y = st[k][r - (1 << son[r - l + 1]) + 1]; 61 if (a[x] > a[y]) return x; 62 return y; 63 } 64 ll solve(int l, int r) 65 { 66 int p = query(l, r); 67 ll ret = sumR[p - 1] - sumR[l - 1] + sumL[r] - sumL[p]; 68 return ret; 69 } 70 int main() 71 { 72 #ifndef ONLINE_JUDGE 73 freopen("input.txt", "r", stdin); 74 //freopen("output.txt", "w", stdout); 75 #endif 76 scanf("%d%d%d", &n, &m, &ty); 77 rep(i, 1, n) a[i] = getint(); 78 init(); 79 ll ans = 0; 80 while (m--) 81 { 82 int l = getint(), r = getint(); 83 if (ty == 1) l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1; 84 if (l > r) swap(l, r); 85 ans = solve(l, r); 86 printf("%lld\n", ans); 87 } 88 #ifndef ONLINE_JUDGE 89 fclose(stdin); fclose(stdout); 90 #endif 91 return 0; 92 }