Description
给定排列aa,如果区间满足max(al+1,al+2,...,ar−1)<almax(al+1,al+2,...,ar−1)<al且max(al+1,al+2,...,ar−1)⩽armax(al+1,al+2,...,ar−1)⩽ar,那么将产生p1p1的贡献否则如果只满足一个条件将产生p2p2的贡献。
多组询问,每次询问一个区间[L,R][L,R]求满足[l,r]∈[L,R][l,r]∈[L,R]的贡献和。
Solution
先预处理一个数aiai左边第一个大于它的位置lili,和右边第一个大于它的位置riri。
- 则区间[li,ri][li,ri]产生p1p1的贡献。可以抽象为一个点(li,ri)(li,ri)
- 若区间左端点为lili,右端点位于(i,rI)(i,rI),可以产生p2p2的贡献。抽象为线段(li,i+1..rl−1)(li,i+1..rl−1)
- 若区间左端点位于(li,i)(li,i),右端点位于rIrI,可以产生p2p2的贡献。抽象为线段(li−1...i−1,rl)(li−1...i−1,rl)
而一个询问区间[L,R][L,R]则可以抽象为一个左下角为[L,L][L,L]右上角为[R,R][R,R]的矩形。
然后离线+扫描线+树状数组即可。
(ps.这里用了一个小技巧:把线段(li,i+1..rl−1)(li,i+1..rl−1)映射为线段(i+1..rl−1,li)(i+1..rl−1,li)。这样更好维护)
#include <bits/stdc++.h>
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;
}