BZOJ 4826: [Hnoi2017]影魔

两种贡献不会同时产生,分开考虑两种贡献
\(pre_i\)\(i\) 之前第一个大于 \(a_i\) 的数,\(suf_i\)\(i\) 之后第一个大于 \(a_i\) 的数,可以单调栈预处理出来
对于第一种贡献

  1. \(i\) 会对 \(i + 1\) 产生 \(p_1\) 的贡献
  2. \(i\) 会对 \(pre_i\)\(suf_i\) 这个点对产生 \(p_1\) 的贡献

相当于对于横坐标 \(pre_i\),纵坐标 \(suf_i\) 处有 \(p_1\) 的贡献

对于第二种贡献
因为满足单调性,而且中间这个数是最大的,那么大于它的端点肯定是 \(pre\) 或者 \(suf\) 之一

  1. 左端点为 \(pre_i\),那么对 \([i + 1, suf_i-1]\)\(p_2\) 的贡献
  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;
}
posted @ 2020-02-15 15:49  Mrzdtz220  阅读(77)  评论(0编辑  收藏  举报