\(HNOI2017影魔\)
- 首先有\(p1\)贡献的区间能发现只有\(O(n)\)个, 具体地,将数字从大到小插入区间,只有这个数的\((位置的)\)前驱后继才有贡献,所以第一部分将询问放在右端点,扫描线就能做
- 对于有\(p2\)贡献的区间,考虑枚举中间最大的数,即求出\(L[i], R[i]\),表示左边右边第一个大于它的位置,
- 具体地只考虑第一种情况即\(a[l] < a[mid] < a[r]\),第二种情况类似,发现只有\(l\in(L[i],i),\ \ r = R[i]\)的区间有贡献,把这些区间都存在右端点, 最后一起取并,直接同上的扫描线做一遍
- 代码写的有点长, 但好歹能过?
#include <bits/stdc++.h>
using namespace std;
#define SZ(x) ((int) ((x).size()))
#define fst first
#define snd second
typedef pair<int, int> pii;
typedef long long ll;
inline int read(int x = 0, int _f = 0)
{
char c = getchar();
for (; !isdigit(c); c = getchar())
_f |= (c == '-');
for (; isdigit(c); c = getchar())
x = x*10 + c-'0';
return _f? -x : x;
}
template <typename T> bool chkmax(T &a, T b)
{
return a < b? a = b, true : false;
}
template <typename T> bool chkmin(T &a, T b)
{
return a > b? a = b, true : false;
}
const int N = 2e5 + 5;
int n, q, p1, p2;
int A[N], P[N];
struct Query
{
int l, r, id;
Query(int l = 0, int r = 0, int id = 0) : l(l), r(r), id(id) {}
}qry[N];
vector<pii> deal[N], arr[N];
ll ans[N];
int R[N], L[N];
struct SegmentTree
{
#define mid ((l + r) >> 1)
#define lc (h << 1)
#define rc (lc | 1)
ll sum[N << 2], addv[N << 2];
inline void clear(int n)
{
for (int i = 1; i <= n << 2; ++i) {
sum[i] = addv[i] = 0;
}
}
inline void push_down(int h, int l, int r)
{
if (addv[h]) {
sum[lc] += addv[h] * (mid - l + 1), addv[lc] += addv[h];
sum[rc] += addv[h] * (r - mid), addv[rc] += addv[h];
addv[h] = 0;
}
}
void modify(int h, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) {
sum[h] += r - l + 1; addv[h] ++;
return ;
}
push_down(h, l, r);
if (ql <= mid) modify(lc, l, mid, ql, qr);
if (qr > mid) modify(rc, mid + 1, r, ql, qr);
sum[h] = sum[lc] + sum[rc];
}
ll query(int h, int l, int r, int ql, int qr)
{
if (qr < ql) return 0;
if (ql <= l && r <= qr) return sum[h];
push_down(h, l, r);
return (ql <= mid? query(lc, l, mid, ql, qr) : 0) +
(qr > mid? query(rc, mid + 1, r, ql, qr) : 0);
}
#undef lc
#undef rc
#undef mid
}SEGT1, SEGT2;
void combine(vector<pii> &A)
{
vector<pii> tmp = A; A.clear();
sort(tmp.begin(), tmp.end());
int l = 0, r = -1;
for (int j = 0; j < SZ(tmp); ++j) {
if (j && tmp[j].fst <= r) {
chkmax(r, tmp[j].snd);
}
else {
if (l <= r) A.push_back(pii(l, r));
l = tmp[j].fst;
r = tmp[j].snd;
}
}
if (l <= r) A.push_back(pii(l, r));
}
void exec()
{
set<int> pos;
for (int i = n; i >= 1; --i) {
auto it = pos.insert(P[i]).fst;
if (it != pos.begin()) {
deal[*it].push_back(pii(*prev(it), 1));
// printf("[%d, %d]\n", *prev(it), *it);
L[P[i]] = *prev(it);
}
if (it != --pos.end()) {
deal[*next(it)].push_back(pii(*it, 1));
// printf("[%d, %d]\n", *it, *next(it));
R[P[i]] = *next(it);
}
}
for (int i = 1; i <= q; ++i) {
deal[qry[i].r].push_back(pii(i, 0));
}
for (int i = 1; i <= n; ++i) if (R[i]) {
if (L[i] + 1 < i) arr[R[i]].push_back(pii(L[i] + 1, i - 1));
}
for (int i = 1; i <= n; ++i) combine(arr[i]);
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < SZ(arr[i]); ++j) {
SEGT2.modify(1, 1, n, arr[i][j].fst, arr[i][j].snd);
}
for (int j = 0; j < SZ(deal[i]); ++j) {
if (!deal[i][j].snd) {
int o = deal[i][j].fst;
ans[qry[o].id] += SEGT2.query(1, 1, n, qry[o].l, qry[o].r-1) * p2;
ans[qry[o].id] += SEGT1.query(1, 1, n, qry[o].l, qry[o].r-1) * p1;
}
else {
SEGT1.modify(1, 1, n, deal[i][j].fst, deal[i][j].fst);
}
}
}
}
void repeatP2()
{
SEGT2.clear(n);
for (int i = 1; i <= n; ++i) arr[i].clear(), deal[i].clear();
for (int i = 1; i <= q; ++i) {
deal[qry[i].l].push_back(pii(i, 0));
}
for (int i = 1; i <= n; ++i) if (L[i]) {
if (i + 1 < R[i]) {
arr[L[i]].push_back(pii(i + 1, R[i] - 1));
}
}
for (int i = 1; i <= n; ++i) combine(arr[i]);
for (int i = n; i >= 1; --i) {
for (int j = 0; j < SZ(arr[i]); ++j) {
SEGT2.modify(1, 1, n, arr[i][j].fst, arr[i][j].snd);
}
for (int j = 0; j < SZ(deal[i]); ++j) {
int o = deal[i][j].fst;
ans[qry[o].id] += SEGT2.query(1, 1, n, qry[o].l+1, qry[o].r) * p2;
}
}
}
int main()
{
freopen("sf.in", "r", stdin);
freopen("sf.out", "w", stdout);
n = read(), q = read(); p1 = read(), p2 = read();
for (int i = 1; i <= n; ++i) {
A[i] = read();
P[A[i]] = i;
L[i] = 0, R[i] = n + 1;
}
for (int i = 1; i <= q; ++i) {
int l = read(), r = read();
qry[i] = Query(l, r, i);
}
exec();
repeatP2();
for (int i = 1; i <= q; ++i) {
printf("%lld\n", ans[i]);
}
return 0;
}