给定排列 a a ,如果区间 (l,r) ( l , r ) 满足 max(al+1,al+2,...,ar−1)<al m a x ( a l + 1 , a l + 2 , . . . , a r − 1 ) < a l 且 max(al+1,al+2,...,ar−1)⩽ar m a x ( a l + 1 , a l + 2 , . . . , a r − 1 ) ⩽ a r ,那么将产生 p1 p 1 的贡献否则如果只满足一个条件将产生 p2 p 2 的贡献。
多组询问,每次询问一个区间 [L,R] [ L , R ] 求满足 [l,r]∈[L,R] [ l , r ] ∈ [ L , R ] 的贡献和。
先预处理一个数 ai a i 左边第一个大于它的位置 li l i ,和右边第一个大于它的位置 ri r i 。
而一个询问区间 [L,R] [ L , R ] 则可以抽象为一个左下角为 [L,L] [ L , L ] 右上角为 [R,R] [ R , R ] 的矩形。
然后离线+扫描线+树状数组即可。
(ps.这里用了一个小技巧:把线段 (li,i+1..rl−1) ( l i , i + 1.. r l − 1 ) 映射为线段 (i+1..rl−1,li) ( i + 1.. r l − 1 , l i ) 。这样更好维护)
#include
using namespace std;
typedef long long lint;
const int maxn = 200005;
int n, m, p1, p2, a[maxn], le[maxn], ri[maxn], stk[maxn], top;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
struct rectangle {
int l, r, y, Id, val;
bool operator < (const rectangle &a) const {
return y < a.y;
}
}s1[maxn * 2], s2[maxn * 3];
#define lowbit(x) ((x) & (-x))
lint ans[maxn], sum1[maxn], sum2[maxn];
inline void add(int x, int a)
{
int t = x;
while (x <= n) {
sum1[x] += a; sum2[x] += (lint)t * a;
x += lowbit(x);
}
}
inline lint query(int x)
{
lint t = x, res = 0;
while (x >= 1) {
res += (t + 1) * sum1[x] - sum2[x];
x -= lowbit(x);
}
return res;
}
int main()
{
n = gi(); m = gi(); p1 = gi(); p2 = gi();
a[0] = a[n + 1] = n + 1;
for (int i = 0; i <= n + 1; ++i) {
if (1 <= i && i <= n) a[i] = gi();
while (top && a[stk[top]] < a[i]) ri[stk[top--]] = i;
le[i] = stk[top];
stk[++top] = i;
}
int tot1 = 0;
for (int l, r, i = 1; i <= m; ++i) {
l = gi(); r = gi(); ans[i] += (r - l) * p1;
if (l > 1) s1[++tot1] = (rectangle) {l, r, l - 1, i, -1};
s1[++tot1] = (rectangle) {l, r, r, i, 1};
}
sort(s1, s1 + tot1 + 1);
int tot2 = 0;
for (int i = 1; i <= n; ++i) {
if (1 <= le[i] && ri[i] <= n) s2[++tot2] = (rectangle) {le[i], le[i], ri[i], 0, p1};
if (le[i] + 1 <= i - 1 && ri[i] <= n) s2[++tot2] = (rectangle) {le[i] + 1, i - 1, ri[i], 0, p2};
if (1 <= le[i] && i + 1 <= ri[i] - 1) s2[++tot2] = (rectangle) {i + 1, ri[i] - 1, le[i], 0, p2};
}
sort(s2, s2 + tot2 + 1);
int k1 = 1, k2 = 1;
for (int i = 1; i <= n && k1 <= tot1; ++i) {
while (k2 <= tot2 && s2[k2].y == i)
add(s2[k2].l, s2[k2].val), add(s2[k2].r + 1, -s2[k2].val), ++k2;
while (k1 <= tot1 && s1[k1].y == i)
ans[s1[k1].Id] += (query(s1[k1].r) - query(s1[k1].l - 1)) * s1[k1].val, ++k1;
}
for (int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
return 0;
}