[洛谷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; }