Luogu3793 由乃救爷爷 分块ST表

Posted itst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3793 由乃救爷爷 分块ST表相关的知识,希望对你有一定的参考价值。

传送门


因为昨天写暴力写挂在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 eq be_r)查询(rmax_l , lmax_r)以及(be_l+1)(be_r-1)的所有块的最大值,三者取(max);如果(be_l = be_r)就暴力

考虑复杂度,设块长为(S),预处理复杂度瓶颈为ST表复杂度(O(frac{N}{S}logfrac{N}{S}));询问复杂度上,如果(be_l eq be_r)(O(1)),否则为(O(S))。因为数据随机,出现(be_l = be_r)的概率为(frac{S}{N}),所以最坏查询复杂度为(O(S^2)),总复杂度为(O(frac{N}{S}logfrac{N}{S} + S^2))

差不多当(S = sqrt[3]{NlogN})的时候有最优复杂度,但是因为数据随机所以块长开大一点也没关系

然后可能需要一些奇怪的常数优化比如把max define掉之类的

#include<bits/stdc++.h>
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;
}

以上是关于Luogu3793 由乃救爷爷 分块ST表的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4865: [Ynoi2017]由乃运椰子

Luogu3792 由乃与大母神原型和偶像崇拜

Luogu P5355 [Ynoi2017]由乃的玉米田

Luogu P3792 由乃与大母神原型和偶像崇拜

luogu 3865模板ST表

ST表——模板(luogu3865)