题意
- 每次询问一个区间的贡献,一个区间的贡献可以这样计算,每存在一个点对满足分别为区间的最大值和次大值就有贡献,满足且或就有贡献
这个题本来也想用莫队做,但实际只能做到,会被卡,要找到一个的做法,我们可以先用单调栈计算出每个点左边第一个比它大的数和每个点右边第一个比它大的数,设为,那么对于每对一定会产生的贡献,对于每个相邻的也会产生的贡献,然后对于每个数来说,会与产生贡献,会与产生贡献,我们可以把所有询问离线下来,依次加入每个位置的贡献,类似于差分的思想加入的时候减去的贡献,加入的时候加回来。对于这些贡献的我们在加入的时候更新的贡献,贡献的我们在加入那个固定点的时候更新一段区间的贡献,那么用一个支持区间修改区间求和的线段树就可以了,复杂度
#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;
}