Description:
提供
p1
p
1
的攻击力:
i,j
i
,
j
位置的数是区间
[i,j]
[
i
,
j
]
的最大值和次大值
提供
p2
p
2
的攻击力:
i,j
i
,
j
位置的数有一个是区间
[i,j]
[
i
,
j
]
的最大值,另一个不是次大值
Solution:
考虑枚举
ai
a
i
,并用单调栈求出左右第一个比
ai
a
i
大的位置
li,ri
l
i
,
r
i
。
p1
p
1
有贡献的区间是左端点为
li
l
i
,右端点为
ri
r
i
p2
p
2
有贡献的区间是左端点为
li
l
i
,右端点为
(i,ri)
(
i
,
r
i
)
,右端点为
ri
r
i
,左端点为
(li,i)
(
l
i
,
i
)
这样我们就可以扫描线+树状数组了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5;
int n, m, p1, p2, tot, top = 1;
ll t1[N], t2[N] , ans[N];
int a[N], st[N], l[N], r[N];
struct seg {
int l, r, p, id, v;
seg() {}
seg(int _l, int _r, int _p, int _id, int _v) : l(_l), r(_r), p(_p), id(_id), v(_v) {}
bool friend operator < (const seg &a, const seg &b) {
return a.p < b.p;
}
} s[N], q[N];
void update(int x, int d) {
for(int i = x; i <= n; i += i & -i) {
t1[i] += d;
t2[i] += x * d;
}
}
ll query(int x) {
ll ret = 0;
for(int i = x; i; i -= i & -i) {
ret += (ll)(x + 1) * t1[i] - t2[i];
}
return ret;
}
int main() {
scanf("%d%d%d%d", &n, &m, &p1, &p2);
a[0] = a[n + 1] = n + 1;
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
while(top && a[i] > a[st[top]]) {
r[st[top]] = i;
--top;
}
l[i] = st[top];
st[++top] = i;
}
for(int i = 1; i <= m; ++i) {
int l, r;
scanf("%d%d", &l, &r);
ans[i] += (r - l) * p1;
q[i] = seg(l, r, l - 1, i, -1);
q[i + m] = seg(l, r, r, i, 1);
}
sort(q + 1, q + 2 * m + 1);
while(top) {
r[st[top--]] = n + 1;
}
for(int i = 1; i <= n; ++i) {
if(l[i] && r[i] <= n) {
s[++tot] = seg(l[i], l[i], r[i], 0, p1);
}
if(r[i] <= n && l[i] + 1 <= i - 1) {
s[++tot] = seg(l[i] + 1, i - 1, r[i], 0, p2);
}
if(l[i] && i + 1 <= r[i] - 1) {
s[++tot] = seg(i + 1, r[i] - 1, l[i], 0, p2);
}
}
sort(s + 1, s + tot + 1);
for(int i = 1, p = 1, j = 1; i <= n; ++i) {
while(j <= tot && s[j].p == i) {
update(s[j].l, s[j].v);
update(s[j].r + 1, -s[j].v);
++j;
}
while(p <= 2 * m && !q[p].p) {
++p;
}
while(p <= 2 * m && q[p].p == i) {
ans[q[p].id] += q[p].v * (query(q[p].r) - query(q[p].l - 1));
++p;
}
}
for(int i = 1; i <= m; ++i) {
printf("%lld\n", ans[i]);
}
return 0;
}