题意
- 每次询问一个区间的贡献,一个区间的贡献可以这样计算,每存在一个点对 ( i , j ) (i,j) (i,j)满足 k i , k j k_i,k_j ki,kj分别为区间 [ i , j ] [i,j] [i,j]的最大值和次大值就有 p 1 p1 p1贡献,满足 ( j − i > 1 (j-i>1 (j−i>1且 k i < max x = i + 1 j − 1 < k j k_i<\max_{x=i+1}^{j-1}<k_j ki<maxx=i+1j−1<kj或 k j < max x = i + 1 j − 1 < k i ) k_j<\max_{x=i+1}^{j-1}<k_i) kj<maxx=i+1j−1<ki)就有 p 2 p2 p2贡献
这个题本来也想用莫队做,但实际只能做到 O ( n n log n ) O(n\sqrt n\log n) O(nnlogn),会被卡,要找到一个 O ( n log n ) O(n\log n) O(nlogn)的做法,我们可以先用单调栈计算出每个点左边第一个比它大的数和每个点右边第一个比它大的数,设为 L i , R i L_i,R_i Li,Ri,那么对于每对 L i , R i L_i,R_i Li,Ri一定会产生 p 1 p1 p1的贡献,对于每个相邻的 i , i + 1 i,i+1 i,i+1也会产生 p 1 p1 p1的贡献,然后对于每个数来说, L i L_i Li会与 [ i + 1 , R i − 1 ] [i+1,R_i-1] [i+1,Ri−1]产生贡献, R i R_i Ri会与 [ L i + 1 , i − 1 ] [L_i+1,i-1] [Li+1,i−1]产生贡献,我们可以把所有询问离线下来,依次加入每个位置的贡献,类似于差分的思想加入 l − 1 l-1 l−1的时候减去 [ l , r ] [l,r] [l,r]的贡献,加入 r r r的时候加回来。对于这些贡献 p 1 p1 p1的我们在加入 R i R_i Ri的时候更新 L i L_i Li的贡献,贡献 p 2 p2 p2的我们在加入那个固定点的时候更新一段区间的贡献,那么用一个支持区间修改区间求和的线段树就可以了,复杂度 O ( n log n ) O(n\log n) O(nlogn)
#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;
}