BZOJ 4826: [Hnoi2017]影魔
两种贡献不会同时产生,分开考虑两种贡献
记 \(pre_i\) 为 \(i\) 之前第一个大于 \(a_i\) 的数,\(suf_i\) 为 \(i\) 之后第一个大于 \(a_i\) 的数,可以单调栈预处理出来
对于第一种贡献
- \(i\) 会对 \(i + 1\) 产生 \(p_1\) 的贡献
- \(i\) 会对 \(pre_i\) 和 \(suf_i\) 这个点对产生 \(p_1\) 的贡献
相当于对于横坐标 \(pre_i\),纵坐标 \(suf_i\) 处有 \(p_1\) 的贡献
对于第二种贡献
因为满足单调性,而且中间这个数是最大的,那么大于它的端点肯定是 \(pre\) 或者 \(suf\) 之一
- 左端点为 \(pre_i\),那么对 \([i + 1, suf_i-1]\) 有 \(p_2\) 的贡献
- 右端点为 \(suf_i\),那么对 \([pre_i+1, i - 1]\) 有 \(p_2\) 的贡献
相当于横坐标上 纵坐标为一个区间有 \(p_2\) 的贡献
查询就相当于二维数点
可以主席树处理也可以扫描线+树状数组
后者常数较小
主席树需要标记永久化支持区间修改
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define lp tree[p].l
#define rp tree[p].r
#define lq tree[q].l
#define rq tree[q].r
#define mid ((l + r) >> 1)
namespace IO {
const int MAXSIZE = 1 << 20;
char buf[MAXSIZE], *p1, *p2;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++)
inline void read() {}
template<typename T, typename ... T2>
inline void read(T &x, T2 &... oth) {
x = 0; T f = 1; char ch = gc();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); }
x *= f;
read(oth...);
}
}
const int N = 2e5 + 7;
struct Seg {
struct Node {
int l, r, tag;
ll sum;
} tree[N * 60];
int tol;
void update(int &p, int q, int l, int r, int x, int y, int v) {
tree[p = ++tol] = tree[q];
tree[p].sum += 1LL * (std::min(y, r) - std::max(l, x) + 1) * v;
if (x <= l && y >= r) {
tree[p].tag += v;
return;
}
if (x <= mid) update(lp, lq, l, mid, x, y, v);
if (y > mid) update(rp, rq, mid + 1, r, x, y, v);
}
ll query(int p, int l, int r, int x, int y) {
if ((x <= l && y >= r) || (!p)) return tree[p].sum;
ll ans = 1LL * (std::min(y, r) - std::max(l, x) + 1) * tree[p].tag;
if (x <= mid) ans += query(lp, l, mid, x, y);
if (y > mid) ans += query(rp, mid + 1, r, x, y);
return ans;
}
ll query(int p, int q, int l, int r, int x, int y) {
return query(p, l, r, x, y) - query(q, l, r, x, y);
}
} seg;
int n, m, p1, p2;
int a[N], pre[N], suf[N], st[N], top;
int root[N];
struct Node {
int l, r, v;
Node() {}
Node(int l, int r, int v): l(l), r(r), v(v) {}
};
std::vector<Node> vec[N];
int main() {
IO::read(n, m, p1, p2);
for (int i = 1; i <= n; i++)
IO::read(a[i]);
st[top = 1] = 0;
for (int i = 1; i <= n; i++) {
while (top > 1 && a[st[top]] < a[i]) top--;
pre[i] = st[top];
st[++top] = i;
}
st[top = 1] = n + 1;
for (int i = n; i >= 1; i--) {
while (top > 1 && a[st[top]] < a[i]) top--;
suf[i] = st[top];
st[++top] = i;
}
for (int i = 1; i <= n; i++) {
if (i < n) vec[i].pb(Node(i + 1, i + 1, p1));
if (pre[i] > 0 && suf[i] <= n) vec[suf[i]].pb(Node(pre[i], pre[i], p1));
if (pre[i] + 1 < i && suf[i] <= n) vec[suf[i]].pb(Node(pre[i] + 1, i - 1, p2));
if (suf[i] - 1 > i && pre[i]) vec[pre[i]].pb(Node(i + 1, suf[i] - 1, p2));
}
for (int i = 1; i <= n; i++) {
root[i] = root[i - 1];
for (int j = 0; j < vec[i].size(); j++) {
seg.update(root[i], root[i], 1, n, vec[i][j].l, vec[i][j].r, vec[i][j].v);
}
}
for (int l, r; m--; ) {
IO::read(l, r);
printf("%lld\n", seg.query(root[r], root[l - 1], 1, n, l, r));
}
return 0;
}
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define mid ((l + r) >> 1)
#define lp p << 1
#define rp p << 1 | 1
namespace IO {
const int MAXSIZE = 1 << 20;
char buf[MAXSIZE], *p1, *p2;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++)
inline void read() {}
template<typename T, typename ... T2>
inline void read(T &x, T2 &... oth) {
x = 0; T f = 1; char ch = gc();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); }
x *= f;
read(oth...);
}
}
const int N = 2e5 + 7;
int n, m, p1, p2;
int a[N], pre[N], suf[N], st[N], top;
ll ans[N];
struct BIT {
int c1[N];
ll c2[N];
inline void clear() {
memset(c1, 0, sizeof(int) * (n + 1));
memset(c2, 0, sizeof(ll) * (n + 1));
}
inline int lowbit(int x) { return x & -x; }
inline void add(int x, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
c1[i] += v;
c2[i] += 1LL * x * v;
}
}
inline void add(int l, int r, int v) {
add(l, v); add(r + 1, -v);
}
inline ll query(int x) {
ll ans = 0;
for (int i = x; i; i -= lowbit(i)) {
ans += 1LL * (x + 1) * c1[i] - c2[i];
}
return ans;
}
inline ll query(int l, int r) {
return query(r) - query(l - 1);
}
} bit;
struct Node {
int l, r, v;
Node() {}
Node(int l, int r, int v): l(l), r(r), v(v) {}
};
struct Query {
int l, r, id;
} Q[N];
bool cmp1(const Query &a, const Query &b) {
return a.r < b.r;
}
bool cmp2(const Query &a, const Query &b) {
return a.l > b.l;
}
std::vector<Node> vec[N], vec2[N];
int main() {
IO::read(n, m, p1, p2);
for (int i = 1; i <= n; i++)
IO::read(a[i]);
st[top = 1] = 0;
for (int i = 1; i <= n; i++) {
while (top > 1 && a[st[top]] < a[i]) top--;
pre[i] = st[top];
st[++top] = i;
}
st[top = 1] = n + 1;
for (int i = n; i >= 1; i--) {
while (top > 1 && a[st[top]] < a[i]) top--;
suf[i] = st[top];
st[++top] = i;
}
for (int i = 1; i <= n; i++) {
if (i < n) vec2[i].pb(Node(i + 1, i + 1, p1));
if (pre[i] > 0 && suf[i] <= n) vec[suf[i]].pb(Node(pre[i], pre[i], p1));
if (pre[i] + 1 < i && suf[i] <= n) vec[suf[i]].pb(Node(pre[i] + 1, i - 1, p2));
if (suf[i] - 1 > i && pre[i]) vec2[pre[i]].pb(Node(i + 1, suf[i] - 1, p2));
}
for (int i = 1; i <= m; i++)
IO::read(Q[i].l, Q[i].r), Q[i].id = i;
std::sort(Q + 1, Q + 1 + m, cmp1);
int cur = 1;
for (int i = 1; i <= m; i++) {
while (cur <= n && cur <= Q[i].r) {
for (int j = 0; j < vec[cur].size(); j++)
bit.add(vec[cur][j].l, vec[cur][j].r, vec[cur][j].v);
cur++;
}
ans[Q[i].id] += bit.query(Q[i].l, Q[i].r);
}
std::sort(Q + 1, Q + 1 + m, cmp2);
bit.clear();
cur = n;
for (int i = 1; i <= m; i++) {
while (cur && cur >= Q[i].l) {
for (int j = 0; j < vec2[cur].size(); j++)
bit.add(vec2[cur][j].l, vec2[cur][j].r, vec2[cur][j].v);
cur--;
}
ans[Q[i].id] += bit.query(Q[i].l, Q[i].r);
}
for (int i = 1; i <= m; i++)
printf("%lld\n", ans[i]);
return 0;
}