1. 程式人生 > >[洛谷P3793]由乃救爺爺

[洛谷P3793]由乃救爺爺

目大意:有$n(n\leqslant2\times10^7)$個數,$m(m\leqslant2\times10^7)$個詢問,每次詢問問區間$[l,r]$中的最大值。保證資料隨機

題解:分塊,處理出每個元素塊中字首最大值和字尾最大值,並且處理出整塊的區間最大值(用$ST$表),然後似乎就可以$O(1)$求區間最大值啦!

然而發現若$l,r$在同一塊中就會出鍋,那就直接暴力查詢(資料隨機)

卡點:

 

C++ Code:

#include <cstdio>
#include <cstring>
#include <algorithm>

namespace GenHelper
{
    unsigned z1,z2,z3,z4,b;
    unsigned rand_()
    {
    b=((z1<<6)^z1)>>13;
    z1=((z1&4294967294U)<<18)^b;
    b=((z2<<2)^z2)>>27;
    z2=((z2&4294967288U)<<2)^b;
    b=((z3<<13)^z3)>>21;
    z3=((z3&4294967280U)<<7)^b;
    b=((z4<<3)^z4)>>12;
    z4=((z4&4294967168U)<<13)^b;
    return (z1^z2^z3^z4);
    }
}
unsigned RAND;
void srand(unsigned x)
{using namespace GenHelper;
z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;}
int read()
{
    using namespace GenHelper;
	static int a, b;
    a=rand_()&32767;
    b=rand_()&32767;
    return a << 15 | b;
}

#define maxn 20000010
#define M 13
const int BSZ = 4480, BNUM = maxn / BSZ + 10;
int n, m, s[maxn];
unsigned long long ans;

int Lmax[maxn], Rmax[maxn];
int L[BNUM], R[BNUM], bel[maxn];

int ST[M + 1][BNUM], LG[BNUM];
inline int query(int l, int r) {
	if (l >= r) return 0;
	static int t; t = LG[r - l];
	return std::max(ST[t][l], ST[t][r - (1 << t)]);
}

int main() {
	scanf("%d%d%u", &n, &m, &RAND); srand(RAND);
	for (int i = 1; i <= n; ++i) {
		s[i] = read();
		bel[i] = i / BSZ + 1;
	}

	const int B = bel[n];
	LG[0] = -1; for (int i = 1; i <= B; ++i) LG[i] = LG[i >> 1] + 1;
	for (int i = 1; i <= B; ++i) {
		L[i] = (i - 1) * BSZ;
		R[i] = L[i] + BSZ - 1;
	}
	L[1] = 1, R[B] = n;
	for (int i = 1, now = 1, last = 0; i <= n; ++i) {
		Lmax[i] = last = std::max(s[i], last);
		if (i >= R[now]) ST[0][now] = Lmax[i], last = 0, ++now;
	}
	for (int i = n, now = B, last = 0; i; --i) {
		Rmax[i] = last = std::max(s[i], last);
		if (i <= L[now]) last = 0, --now;
	}
	for (int i = 1, pw = 1; i <= M; ++i, pw <<= 1) {
		for (int j = 1; j <= B; ++j) ST[i][j] = std::max(ST[i - 1][j], ST[i - 1][std::min(j + pw, B)]);
	}

	while (m --> 0) {
		int l = read() % n + 1, r = read() % n + 1;
		if (l > r) std::swap(l, r);
		const int lb = bel[l], rb = bel[r];
		if (lb != rb) {
			ans += std::max(std::max(Rmax[l], Lmax[r]), query(lb + 1, rb));
		} else {
			static int res; res = 0;
			for (int i = l; i <= r; ++i) res = std::max(res, s[i]);
			ans += res;
		}
	}
	printf("%llu\n", ans);
	return 0;
}