正题
题目链接:https://www.luogu.com.cn/problem/P3793
题目大意
给出nnn个数字的一个序列mmm次询问区间最大值
保证数据随机
1≤n,m≤2×1071\leq n,m\leq 2\times 10^71≤n,m≤2×107
解题思路
使用STSTST表可以做到O(1)O(1)O(1)询问,但是预处理的时空复杂度都是O(nlogn)O(n\log n)O(nlogn),且自带大常数导致过不了。
如何加快预处理的时间,(因为是lxl的题目所以)考虑使用分块。每次询问可以分为整块的部分和不是整块的零散部分。
去掉没有跨块的情况,那么零散的部分就是块内前后缀最大值。然后整块的部分用STSTST表就好了。
那么没有跨块的情况是不是还需要给每个块维护一个STSTST表?这样空间还是过不了,其实可以考虑将没有跨块的情况按顺序每个块每个块离线处理,这样就可以过了。
但是数据保证随机,所以随机到同一个块内的概率是1T\frac{1}{T}T1,也就是期望n\sqrt nn次,暴力处理是O(n)O(\sqrt n)O(n)的,所以直接暴力处理就可以了
时间复杂度O(nlogn+m)O(n\log\sqrt n+m)O(nlogn+m)。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e7+10;
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;
}
int n,m,a[N],lg[N],p[N],q[N],g[5000][13];
int L[5000],R[5000],pos[N];
unsigned s;
unsigned long long ans;
int AskT(int l,int r){if(l>r)return 0;int z=lg[r-l+1];return max(g[l][z],g[r-(1<<z)+1][z]);
}
int main()
{scanf("%d%d%u",&n,&m,&s);srand(s);for(int i=1;i<=n;i++)a[i]=read();int T=sqrt(n);for(int i=1;i<=T;i++)L[i]=R[i-1]+1,R[i]=i*T;if(R[T]!=n)++T,L[T]=R[T-1]+1,R[T]=n;for(int i=1;i<=T;i++){for(int j=L[i];j<=R[i];j++)pos[j]=i,g[i][0]=max(g[i][0],a[j]);p[L[i]]=a[L[i]];q[R[i]]=a[R[i]];for(int j=L[i]+1;j<=R[i];j++)p[j]=max(p[j-1],a[j]);for(int j=R[i]-1;j>=L[i];j--)q[j]=max(q[j+1],a[j]);}for(int j=1;(1<<j)<=T;j++)for(int i=1;i+(1<<j)-1<=T;i++)g[i][j]=max(g[i][j-1],g[i+(1<<j-1)][j-1]);for(int i=2;i<=T;i++)lg[i]=lg[i>>1]+1;for(int i=1;i<=m;i++){int l=read(),r=read();l=l%n+1;r=r%n+1;if(l>r)swap(l,r);int x=pos[l],y=pos[r];int tmp=0;if(x==y){for(int i=l;i<=r;i++)tmp=max(tmp,a[i]);}else{tmp=AskT(x+1,y-1);tmp=max(tmp,max(q[l],p[r]));}ans+=tmp;}printf("%llu\n",ans);
}