题面
题解
对于两个位置(l, r),如果它们分别是区间([l, r])的最大值,那么可以产生(p1)的贡献,
否则如果它们中有一个是最大值,那么可以产生(p2)的贡献。
所以对于当前位置(i),假设左右两边第一个比它大的是(l, r),那么([l, r])可以产生p1的贡献,([l + 1 sim i - 1, r])和([l, i + 1sim r - 1])会产生(p2)的贡献。
于是加完(R[i])后,对(L[i])产生(p1)的贡献
加完位置(L[i])后,对((i, R[i]))产生(p2)的贡献
加完位置(R[i])后,对((L[i], i))产生(p2)的贡献
那么对于一个询问(L, R),只要考虑它范围内的贡献,于是也拆成三个部分
加入完(L - 1)时,要忽略前面(L, R)位置产生的所有贡献
加入完(R)时,要考虑所有的(L, R)位置产生的贡献
还有每一组的([i, i + 1])产生的贡献(p1)
这样的话,用扫描线+区间加法+区间求和即可。
用单调栈和树状数组就行了。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x))
namespace IO
{
const int BUFSIZE = 1 << 20;
char ibuf[BUFSIZE], *is = ibuf, *it = ibuf;
inline char getchar() { if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); return *is++; }
}
inline int read()
{
int data = 0, w = 1;
char ch = IO::getchar();
while(ch != '-' && (ch < '0' || ch > '9')) ch = IO::getchar();
if(ch == '-') w = -1, ch = IO::getchar();
while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::getchar();
return data * w;
}
const int maxn(2e5 + 10);
int n, m, p1, p2, stk[maxn], top, cnt, tot;
int L[maxn], R[maxn], a[maxn];
long long c1[maxn], c2[maxn], ans[maxn];
struct upd { int x, l, r, v; } p[maxn << 2];
struct qry { int x, l, r, v, id; } q[maxn << 2];
inline int operator < (const upd &a, const upd &b) { return a.x < b.x; }
inline int operator < (const qry &a, const qry &b) { return a.x < b.x; }
void add(int x, int w)
{
for(RG int i = x; i <= n; i += i & -i)
c1[i] += w, c2[i] += x * w;
}
long long query(int x)
{
long long ans = 0;
for(RG int i = x; i; i -= i & -i)
ans += (x + 1) * c1[i] - c2[i];
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
file(cpp);
#endif
n = read(), m = read(), p1 = read(), p2 = read();
for(RG int i = 1; i <= n; i++) a[i] = read();
stk[top = 0] = 0;
for(RG int i = 1; i <= n; i++)
{
while(top && a[stk[top]] < a[i]) --top;
L[i] = stk[top], stk[++top] = i;
}
stk[top = 0] = n + 1;
for(RG int i = n; i; i--)
{
while(top && a[stk[top]] < a[i]) --top;
R[i] = stk[top], stk[++top] = i;
}
for(RG int i = 1; i <= m; i++)
{
int l = read(), r = read(); ans[i] = (r - l) * p1;
q[++cnt] = (qry) {r, l, r, 1, i};
q[++cnt] = (qry) {l - 1, l, r, -1, i};
}
std::sort(q + 1, q + cnt + 1);
for(RG int i = 1; i <= n; i++)
{
if(L[i] && R[i] < n + 1) p[++tot] = (upd) {R[i], L[i], L[i], p1};
if(L[i] && R[i] > i + 1) p[++tot] = (upd) {L[i], i + 1, R[i] - 1, p2};
if(L[i] + 1 < i && R[i] < n + 1)
p[++tot] = (upd) {R[i], L[i] + 1, i - 1, p2};
}
std::sort(p + 1, p + tot + 1);
for(RG int i = 1, j = 1; i <= cnt; i++)
{
while(j <= tot && p[j].x <= q[i].x)
add(p[j].l, p[j].v), add(p[j].r + 1, -p[j].v), ++j;
ans[q[i].id] += q[i].v * (query(q[i].r) - query(q[i].l - 1));
}
for(RG int i = 1; i <= m; i++) printf("%lld
", ans[i]);
return 0;
}