题解:P14638 [NOIP2025] 序列询问 / query(民间数据)
思路
注意到
设求出来的离散化数组
枚举区间的左端点
那
那什么条件下才有
回顾之前的做法,我们需要求出
当我们求出 但是我不会,于是考场编了一个离线
考虑对
考虑移动右端点时如何维护这样的结构。注意到单调栈的增加只会在
综上,这个做法理论复杂度是
实际上我考场调完第一部分(求出
还有一个问题是
代码
拼尽全力卡常还是在洛谷卡不进去,最慢的点 2.07s,就算过了吧。
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
int n,a[50010]; int qzh[50010];
int st[20][50010];
inline int query(int l,int r)
{
return max(st[__lg(r-l+1)][l],st[__lg(r-l+1)][r-(1<<__lg(r-l+1))+1]);
}
int sst[20][50010];
inline int qquery(int l,int r)
{
return min(sst[__lg(r-l+1)][l],sst[__lg(r-l+1)][r-(1<<__lg(r-l+1))+1]);
}
int m,l[2110],r[2110],ll[2110],rr[2110];
int tot=0,lsh[2110];
int ttot=0,gt[2110];
int ans[2110][50010];
int now[50010];
int bg,ed,q[50010];
ull sum[1050];
int stt[12][2110];
inline int queryy(int l,int r)
{
return max(stt[__lg(r-l+1)][l],stt[__lg(r-l+1)][r-(1<<__lg(r-l+1))+1]);
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n;
for(int i=1; i<=n; ++i) cin>>a[i],qzh[i]=qzh[i-1]+a[i],st[0][i]=sst[0][i]=qzh[i];
for(int i=1; i<=17; ++i)
{
for(int j=0; j<=n-(1<<i)+1; ++j)
{
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
sst[i][j]=min(sst[i-1][j],sst[i-1][j+(1<<i-1)]);
}
}
cin>>m;
for(int i=1; i<=m; ++i) cin>>l[i]>>r[i],lsh[++tot]=l[i],lsh[++tot]=r[i]+1;
sort(lsh+1,lsh+tot+1),tot=unique(lsh+1,lsh+tot+1)-lsh-1;
gt[ttot=1]=1;
for(int i=1; i<=tot; ++i)
{
while(gt[ttot]*2<lsh[i]) ++ttot,gt[ttot]=gt[ttot-1]*2;
if(gt[ttot]!=lsh[i]) gt[++ttot]=lsh[i];
}
tot=ttot,memcpy(lsh,gt,sizeof(gt));
int ax=0;
for(int i=1; i<=m; ++i)
{
ll[i]=lower_bound(lsh+1,lsh+tot+1,l[i])-lsh;
rr[i]=lower_bound(lsh+1,lsh+tot+1,r[i]+1)-lsh-1;
ax=max(ax,__lg(rr[i]-ll[i]+1));
}
int B=(n+1-1)/1;
for(int L=1,R; L<=n; L=R+1)
{
R=min(L+B-1,n);
memset(ans,-0x3f,sizeof(ans));
for(int j=1; j<=tot-1; ++j)
{
bg=1,ed=0;
for(int i=max(L-lsh[j]+1,1); i<=R; ++i)
{
int r1=i+lsh[j]-1,r2=min(i+lsh[j+1]-2,n);
if(r1<=n)
{
now[i]=query(r1,r2)-qzh[i-1];
while(ed>=bg && now[q[ed]]<=now[i]) --ed;
q[++ed]=i;
}
if(i>=L)
{
while(bg<=ed && q[bg]<i-lsh[j]+1) ++bg;
ans[j][i-L]=max(ans[j][i-L],now[q[bg]]);
}
}
bg=1,ed=0;
for(int i=min(R+lsh[j]-1,n); i>=L; --i)
{
int r1=i-lsh[j]+1,r2=max(i-lsh[j+1]+2,1);
if(r1>=1)
{
now[i]=qzh[i]-qquery(r2-1,r1-1);
while(ed>=bg && now[q[ed]]<=now[i]) --ed;
q[++ed]=i;
}
if(i<=R)
{
while(bg<=ed && q[bg]>i+lsh[j]-1) ++bg;
ans[j][i-L]=max(ans[j][i-L],now[q[bg]]);
}
}
}
for(int j=L; j<=R; ++j)
{
for(int k=1; k<=tot; ++k) stt[0][k]=ans[k][j-L];
for(int k=1; k<=ax; ++k)
{
for(int l=1; l<=tot-(1<<k)+1; ++l)
{
stt[k][l]=max(stt[k-1][l],stt[k-1][l+(1<<k-1)]);
}
}
for(int i=1; i<=m; ++i) sum[i]^=(ull)j*queryy(ll[i],rr[i]);
}
}
for(int i=1; i<=m; ++i) cout<<sum[i]<<'\n';
return 0;
}