传送门
因为昨天写暴力写挂在UOJ上用快排惨遭卡常,所以今天准备写一个卡常题消遣消遣,然后时间又垫底了QAQ
这道题显然需要支持一个\(O(N)\)预处理\(O(1)\)查询的ST表,显然普通的ST表是做不到的,因为预处理的时间太长了
于是分块优化掉ST表的预处理
约定\(L_i,R_i\)表示第\(i\)个块的左端点和右端点,\(be_i\)表示第\(i\)个数所在的块
对于每一个位置\(i\)预处理\(L_{be_i}\)到\(i\)的所有数的最大值\(lmax_i\)以及\(i\)到\(R_{be_i}\)的所有数的最大值\(rmax_i\);预处理块最大值的ST表
对于一个询问\((l,r)\),如果\(be_i \neq be_r\)查询\(rmax_l , lmax_r\)以及\(be_l+1\)到\(be_r-1\)的所有块的最大值,三者取\(max\);如果\(be_l = be_r\)就暴力
考虑复杂度,设块长为\(S\),预处理复杂度瓶颈为ST表复杂度\(O(\frac{N}{S}log\frac{N}{S})\);询问复杂度上,如果\(be_l \neq be_r\)为\(O(1)\),否则为\(O(S)\)。因为数据随机,出现\(be_l = be_r\)的概率为\(\frac{S}{N}\),所以最坏查询复杂度为\(O(S^2)\),总复杂度为\(O(\frac{N}{S}log\frac{N}{S} + S^2)\)
差不多当\(S = \sqrt[3]{NlogN}\)的时候有最优复杂度,但是因为数据随机所以块长开大一点也没关系
然后可能需要一些奇怪的常数优化比如把max define掉之类的
#include
using namespace std;
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);
}
}
void srand(unsigned x)
{
using namespace GenHelper;
z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;
}
int read()
{
using namespace GenHelper;
int a=rand_()&32767;
int b=rand_()&32767;
return a*32768+b;
}
const int MAXN = 2e7 + 7;
unsigned int arr[MAXN] , maxN1[MAXN] , maxN2[MAXN] , ST[15][26000] , logg2[26000];
unsigned int N , M , S , T , cnt;
#define cmp(a , b) ((a) > (b) ? (a) : (b))
inline unsigned int qST(int x , int y){
if(x > y)
return 0;
int t = logg2[y - x + 1];
return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
}
int main(){
cin >> N >> M >> S;
srand(S);
T = pow(N * log2(N) , 1.0/3);
cnt = N / T + (N % T ? 1 : 0);
for(int i = 1 ; i <= N ; ++i){
arr[i] = read();
maxN2[i] = arr[i];
if(i % T != 1)
maxN2[i] = cmp(maxN2[i] , maxN2[i - 1]);
}
for(int i = N ; i ; --i){
maxN1[i] = arr[i];
if(i % T)
maxN1[i] = cmp(maxN1[i] , maxN1[i + 1]);
if(i % T == 1)
ST[0][i / T + 1] = maxN1[i];
}
for(int i = 2 ; i <= cnt ; ++i)
logg2[i] = logg2[i >> 1] + 1;
for(int i = 1 ; 1 << i <= cnt ; ++i)
for(int j = 1 ; j + (1 << i) - 1 <= cnt ; ++j)
ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
unsigned long long sum = 0;
while(M--){
int l = read() % N + 1 , r = read() % N + 1;
if(l > r)
swap(l , r);
if((l - 1) / T == (r - 1) / T){
unsigned int ans = 0;
for(int i = l ; i <= r ; ++i)
ans = cmp(ans , arr[i]);
sum += ans;
}
else
sum += cmp(cmp(maxN1[l] , maxN2[r]) , qST((l - 1) / T + 2 , (r - 1) / T));
}
cout << sum;
return 0;
}