hh弟中弟 @ 2024-12-22 15:30:27
RT,写的分块 st 表,块长 32,T 了两个点,发现是询问 T 了,预处理跑了不到一秒。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pii std::pair<int,int>
#define eb emplace_back
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
std::mt19937_64 myrand(std::chrono::high_resolution_clock::now().time_since_epoch().count());
inline int R(int n){return myrand()%n+1;}
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 N=2e7+5,inf=1e9,len=32;
inline void Min(int &x,int y){if(x>y)x=y;}
inline void Max(int &x,int y){if(x<y)x=y;}
int n,m,id[N],a[N],St[20][N/len+1],num;
short st[6][N];
ull ans;
inline int fl(int id){return (id-1)*len+1;}
inline int fr(int id){return std::min(n,fl(id)+len-1);}
inline int get(int id,int x,int y){int L=fl(id);return a[L+x]>a[L+y]?x:y;}
inline int getsan(int id,int l,int r){
if(l>r)return 0;
int L=fl(id);int d=std::__lg(r-l+1);
return a[L+get(id,st[d][l],st[d][r-(1<<d)+1])];
}
inline int getz(int l,int r){
if(l>r)return 0;int d=std::__lg(r-l+1);
return std::max(St[d][l],St[d][r-(1<<d)+1]);
}
signed main(){
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
int zc;std::cin>>n>>m>>zc;srand(zc);num=(n-1)/len+1;
for(int i=1;i<=n;++i){
a[i]=read();id[i]=(i-1)/len+1;Max(St[0][id[i]],a[i]);
}
for(int i=1;i<=num;++i){
int l=fl(i),r=fr(i),id=i;
for(int i=l;i<=r;++i)st[0][i]=i-l;
for(int i=1;i<=5;++i)for(int j=l;j+(1<<i)-1<=r;++j)
st[i][j]=get(id,st[i-1][j],st[i-1][j+(1<<i-1)]);
}
for(int i=1;i<=std::__lg(num);++i)for(int j=1;j+(1<<i)-1<=num;++j)
St[i][j]=std::max(St[i-1][j],St[i-1][j+(1<<i-1)]);
for(int i=1;i<=m;++i){
int l=read()%n+1,r=read()%n+1;if(l>r)std::swap(l,r);
int lid=id[l],rid=id[r],R=fr(lid),L=fl(rid);
if(lid==rid){ans+=(getsan(lid,l,r));continue;}
ans+=std::max(std::max(getsan(lid,l,R),getsan(rid,L,r)),getz(lid+1,rid-1));
}std::cout<<ans<<'\n';
}
by hh弟中弟 @ 2024-12-22 15:31:28
这一部分 T 了。
for(int i=1;i<=m;++i){
int l=read()%n+1,r=read()%n+1;if(l>r)std::swap(l,r);
int lid=id[l],rid=id[r],R=fr(lid),L=fl(rid);
if(lid==rid){ans+=(getsan(lid,l,r));continue;}
ans+=std::max(std::max(getsan(lid,l,R),getsan(rid,L,r)),getz(lid+1,rid-1));
}std::cout<<ans<<'\n';
by wangziyue_AK @ 2024-12-22 15:36:09
查询函数里的
std::__lg(r-l+1)
太慢了,建议预处理log
by wangziyue_AK @ 2024-12-22 15:37:20
@hh弟中弟
by hh弟中弟 @ 2024-12-22 15:38:51
@wangziyue_AK
额,预处理之后的也 T
by wangziyue_AK @ 2024-12-22 15:44:42
@hh弟中弟 建议少一些函数调用,块的左右端点都能预处理
by hh弟中弟 @ 2024-12-22 15:45:38
@wangziyue_AK
改成前后缀预处理后用 C++98 过了。
by 5k_sync_closer @ 2024-12-22 15:46:32
@wangziyue_AK lg 是用 builtin_clz 写的,常数很小
by wangziyue_AK @ 2024-12-22 15:48:31
@5k_sync_closer哦,那我之前听了一些误人子弟的讲解,自己也开始犯傻了,谢谢