HNOI2017影魔

\(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;
}

posted @ 2018-03-29 22:24  pbvrvnq  阅读(155)  评论(0编辑  收藏  举报