bzoj3956: Count (單調棧+st表)
阿新 • • 發佈:2019-03-26
getc 解決 我們 一半 void pro main 解決問題 ast 之間的點對,\(y\)一定不會越過\(pos\)
題面鏈接
bzoj
題解
非常巧妙的一道題
類似[hnoi影魔]
每個點會給左右第一個大於它的點對產生貢獻
可以用單調棧求出
這裏有點小細節,就是處理相等的點時,最左邊的點管左邊的貢獻,最右邊的點管最右邊的貢獻
然後對於每個點,求出了一對\(x, y\)
那麽,對於詢問區間\(l,r\)
答案就是有多少個\(x,y\)在區間\(l,r\)之間, 即\(l<=x<=r\) && \(l<=y<=r\)
再加上相鄰的點對
這就可以用二維數點做
但是有沒有更優秀的做法呢?
我們設\(a[pos]\)為區間\([l,r]\)之間最大的數
那麽\(x\)在\([l,pos-1]\)
那麽只要求出\([l,pos-1]\)之間有多少\(x\),就可以求出有多少點對\((x,y)\)在\([l,pos-1]\)
同理另一半也可以求出
那麽,前綴和就可以解決問題了
Code
#include<bits/stdc++.h> #define LL long long #define RG register using namespace std; template<class T> inline void read(T &x) { x = 0; RG char c = getchar(); bool f = 0; while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1; while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar(); x = f ? -x : x; return ; } template<class T> inline void write(T x) { if (!x) {putchar(48);return ;} if (x < 0) x = -x, putchar('-'); int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10; for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ; } const int N = 300010; int n, m, a[N]; int f[21][N], g[21][N]; int query(int l, int r) { int k = log2(r - l + 1); if (f[k][l] >= f[k][r - (1 << k) + 1]) return g[k][l]; return g[k][r - (1 << k) + 1]; } int L[N], R[N]; int suml[N], sumr[N]; int q[N]; int main() { int type; read(n), read(m), read(type); for (int i = 1; i <= n; i++) read(a[i]), f[0][i] = a[i], g[0][i] = i; for (int j = 1; j <= 20; j++) for (int i = 1; i + (1 << j) - 1 <= n; i++) if (f[j - 1][i] >= f[j - 1][i + (1 << (j - 1))]) { f[j][i] = f[j - 1][i]; g[j][i] = g[j - 1][i]; } else { f[j][i] = f[j - 1][i + (1 << (j - 1))]; g[j][i] = g[j - 1][i + (1 << (j - 1))]; } int top = 0; for (int i = 1; i <= n; i++) { while (top && a[q[top]] < a[i]) top--; if (top && a[i] != a[q[top]]) L[i] = q[top]; q[++top] = i; } top = 0; for (int i = n; i; i--) { while (top && a[q[top]] < a[i]) top--; if (top && a[i] != a[q[top]]) R[i] = q[top]; q[++top] = i; } /*for (int i = 1; i <= n; i++) printf("%d %d\n", L[i], R[i]);*/ for (int i = 1; i <= n; i++) suml[L[i]]++, sumr[R[i]]++; for (int i = 1; i <= n; i++) suml[i] += suml[i - 1], sumr[i] += sumr[i - 1]; int lastans = 0; while (m--) { int x, y, l, r; read(x), read(y); if (type) l = (x + lastans - 1) % n + 1, r = (y + lastans - 1) % n + 1; else l = x, r = y; if (l > r) swap(l, r); int pos = query(l, r); lastans = suml[pos - 1] - suml[l - 1] + sumr[r] - sumr[pos] + r - l; printf("%d\n", lastans); } return 0; }
bzoj3956: Count (單調棧+st表)