LOJ 6057 - [HNOI2016]序列 加强版再加强版

Description

给定一个长度为 \(n\le 3*10^6\) 的序列
\(q\le 10^7\) 次询问每次求区间 \([l,r]\) 的所有子区间的最小值的和
询问随机

Solution

考虑求出区间的最小值, 设在位置 \(p\)
考虑 \([l, p)\)\((p, r]\) 的答案
\([l, p) = [l, n] - [p, n] - (左端点在[l, p) 右端点在[p, n] 的)\)
因为 \([l, p)\) 都比 \(p\)
所以该部分为 \((p-l) * 左端点在p的答案\)

区间最小值可以用rmq求
正常的O(n)-O(1) rmq需要转成树, 然后变成 \(\pm 1\) 的, 然后分块块内还要预处理, 常数很大
注意到这题询问随机, 询问到块内的几率很小, 所以可以把块内的处理改成暴力
块边缘维护前后缀min即可

Code

#include <bits/stdc++.h>
using namespace std;
#define ri rd<int>
#define rep(i, a, b) for (int i = (a), _ = (b); i <= _; ++i)
#define per(i, a, b) for (int i = (a), _ = (b); i >= _; --i)
#define For(i, a, b) for (int i = (a), _ = (b); i < _; ++i)
const int maxN = 3e6 + 7;
const int INF = 1e9 + 7;
typedef long long LL;
const LL O = 1e9 + 7;

template<class T> T rd() {
	bool f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
	T x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; return f ? x : -x;
}

int n, m;
int a[maxN];

namespace IO {
	int A, B, C, P;
	LL lastAns;

	inline int rnd() {
		return A = (A * B + (C ^ (int)(lastAns & 0x7fffffffLL)) % P) % P;	
	}

	void init() {
		A = ri(), B = ri(), C = ri(), P = ri();
		lastAns = 0;
	}
}

namespace RMQ {
	const int maxL = 3e5 + 7;
	const int B = 12;
	struct Node {
		int l, r, v;
		int pre[12], suf[12];
	}a[maxL];

	int st[maxL][20];
	int ln[maxL];
	int bl[maxN];

	void gmin(int &x, int y) {
		if (::a[y] < ::a[x]) x = y;
	}

	int ggmin(int x, int y) {
		return ::a[x] < ::a[y] ? x : y;
	}

	void init() {
		rep (i, 1, n) {
			int &t = bl[i] = i / B;
			int &v = st[t][0];
			if (a[t].l == 0) {
				a[t].l = i;
				v = i;
			}
			a[t].r = i;
			gmin(v, i);
		}

		int T = bl[n];
		rep (j, 0, T) {
			Node &t = a[j];
			int l = t.l, r = t.r;
			t.pre[0] = l;
			rep (i, l+1, r) t.pre[i-l] = ggmin(t.pre[i-l-1], i);
			t.suf[0] = r;
			per (i, r-1, l) t.suf[r-i] = ggmin(t.suf[r-i-1], i);
		}

		rep (i, 2, T) ln[i] = ln[i >> 1] + 1;
		per (i, T, 0) {
			rep (j,	1, ln[T-i+1])
				st[i][j] = ggmin(st[i][j-1], st[i+(1<<(j-1))][j-1]);
		}
	}

	int eval(int l, int r) {
		int len = ln[r-l+1];
		return ggmin(st[l][len], st[r-(1<<len)+1][len]);
	}

	int get(int l, int r) {
		int res = l;
		if (bl[l] == bl[r]) {
			rep (i, l, r) gmin(res, i);
			return res;
		}
		int u = bl[l], v = bl[r];
		gmin(res, a[u].suf[a[u].r - l]);
		gmin(res, a[v].pre[r - a[v].l]);
		if (u+1 < v) gmin(res, eval(u+1, v-1));
		return res;
	}
}

namespace Solve {
	LL pre[maxN], suf[maxN];

	void init() {
		static int stack[maxN], Top;
		stack[Top = 0] = 0;
		LL res = 0;
		rep (i, 1, n) {
			for (; Top && a[stack[Top]] >= a[i]; --Top)
				res -= 1LL * a[stack[Top]] * (stack[Top] - stack[Top-1]);
			stack[++Top] = i;
			res += 1LL * a[i] * (stack[Top] - stack[Top-1]);
			pre[i] = res;
		}
		res = 0;
		per (i, n, 1) {
			for (; Top && a[stack[Top]] >= a[i]; --Top)
				res -= 1LL * a[stack[Top]] * (stack[Top-1] - stack[Top]);
			stack[++Top] = i;
			res += 1LL * a[i] * (stack[Top-1] - stack[Top]);
			suf[i] = res;
		}
		rep (i, 1, n) pre[i] += pre[i-1];
		per (i, n, 1) suf[i] += suf[i+1];
	}

	LL getr(int l, int r) {
		return suf[l] - suf[r] - 1LL * (r-l) * (suf[r] - suf[r+1]);
	}

	LL getl(int l, int r) {
		return pre[r] - pre[l] - 1LL * (r-l) * (pre[l] - pre[l-1]);
	}
}

LL get(int l, int r) {
	int p = RMQ::get(l, r);	
	LL res = 1LL * (p-l+1) * (r-p+1) * a[p];
	if (l < p) res += Solve::getr(l, p);
	if (p < r) res += Solve::getl(p, r);
	return res;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif

	n = ri(), m = ri();
	rep (i, 1, n) a[i] = ri();
	IO::init();
	RMQ::init();
	Solve::init();

	LL res = 0;
	rep (i, 1, m) {
		int l = IO::rnd() % n + 1, r = IO::rnd() % n + 1;
		if (l > r) std::swap(l, r);
		LL &tp = IO::lastAns = get(l, r);
		res += tp % O;
	}
	printf("%lld\n", (res % O + O) % O);

	return 0;
}
posted @ 2018-05-14 18:41  _zwl  阅读(228)  评论(0编辑  收藏  举报