題意
- 每次詢問一個區間的貢獻,一個區間的貢獻可以這樣計算,每存在一個點對滿足分別爲區間的最大值和次大值就有貢獻,滿足且或就有貢獻
這個題本來也想用莫隊做,但實際只能做到,會被卡,要找到一個的做法,我們可以先用單調棧計算出每個點左邊第一個比它大的數和每個點右邊第一個比它大的數,設爲,那麼對於每對一定會產生的貢獻,對於每個相鄰的也會產生的貢獻,然後對於每個數來說,會與產生貢獻,會與產生貢獻,我們可以把所有詢問離線下來,依次加入每個位置的貢獻,類似於差分的思想加入的時候減去的貢獻,加入的時候加回來。對於這些貢獻的我們在加入的時候更新的貢獻,貢獻的我們在加入那個固定點的時候更新一段區間的貢獻,那麼用一個支持區間修改區間求和的線段樹就可以了,複雜度
#include <bits/stdc++.h>
#define ll long long
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 2e5 + 10;
ll ans[N];
int a[N], L[N], R[N], Sta[N];
int n, m, p1, p2, top, cnt;
struct Segment_Tree {
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r
ll S[N << 2], lazy[N << 2];
void modify(int bh, int l, int r, int z) {
lazy[bh] += z, S[bh] += 1ll * (r - l + 1) * z;
}
void pushup(int bh) {
S[bh] = S[ls] + S[rs];
}
void pushdown(int bh, int l, int r) {
if (lazy[bh]) {
modify(lson, lazy[bh]), modify(rson, lazy[bh]);
lazy[bh] = 0;
}
}
void update(int bh, int l, int r, int x, int y, int z) {
if (x <= l && r <= y) modify(bh, l, r, z);
else {
pushdown(bh, l, r);
if (x <= mid) update(lson, x, y, z);
if (y > mid) update(rson, x, y, z);
pushup(bh);
}
}
ll query(int bh, int l, int r, int x, int y) {
if (x <= l && r <= y) return S[bh];
pushdown(bh, l, r);
if (y <= mid) return query(lson, x, y);
if (x > mid) return query(rson, x, y);
return query(lson, x, y) + query(rson, x, y);
}
}T;
struct Que {
int opt, pos, l, r, val, id;
bool operator < (const Que &Tp) const {
if (pos == Tp.pos) return opt < Tp.opt;
return pos < Tp.pos;
}
}Q[N << 3];
int main() {
#ifdef ylsakioi
freopen("2019.in", "r", stdin);
freopen("2019.out", "w", stdout);
#endif
int x, y;
scanf("%d%d%d%d", &n, &m, &p1, &p2);
For(i, 1, n) scanf("%d", &a[i]);
For(i, 1, n) {
for (; top && a[Sta[top]] < a[i]; -- top)
R[Sta[top]] = i;
L[i] = Sta[top], Sta[++ top] = i;
}
while (top --) R[Sta[top + 1]] = n + 1;
For(i, 1, n) {
if (i < n) Q[++ cnt] = (Que) {0, i + 1, i, i, p1, 0};
if (1 <= L[i] && R[i] <= n)
Q[++ cnt] = (Que) {0, R[i], L[i], L[i], p1, 0};
if (1 <= L[i] && R[i] > i + 1)
Q[++ cnt] = (Que) {0, L[i], i + 1, R[i] - 1, p2, 0};
if (L[i] < i - 1 && R[i] <= n)
Q[++ cnt] = (Que) {0, R[i], L[i] + 1, i - 1, p2, 0};
}
For(i, 1, m) {
scanf("%d%d", &x, &y);
Q[++ cnt] = (Que) {1, x - 1, x, y, -1, i};
Q[++ cnt] = (Que) {1, y, x, y, 1, i};
}
sort(Q + 1, Q + cnt + 1);
For(i, 1, cnt) {
if (Q[i].opt) ans[Q[i].id] += T.query(1, 1, n, Q[i].l, Q[i].r) * Q[i].val;
else T.update(1, 1, n, Q[i].l, Q[i].r, Q[i].val);
}
For(i, 1, m) printf("%lld\n", ans[i]);
return 0;
}