SP20644 ZQUERY - Zero Query
SP20644 (回滚莫队)
题目很简单,给出一个只包含
求区间和这一操作可以在读入的时候预处理前缀和,要求
考虑使用莫队算法,显然增加操作是很简单的,可以很容易地进行转移。但是删除操作不好完成,因此普通莫队的方法被舍弃掉。而对于这一类问题,回滚莫队可以很有效地解决。
回滚莫队最主要的用途是求一类增加容易删除困难(增加困难删除容易)的问题。既然另一种操作不好完成,那我就只用一种操作。
首先将询问离线,以左端点所在块为第一关键字,右端点为第二关键字进行排序。对于左端点在相同块中的询问,显然右端点只需要向右递增即可,最大时间复杂度为
对于一些细节,首先因为原序列中含有
#pragma GCC optimize(2)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#include<time.h>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
k=0;
T flag=1;char b=getchar();
while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
k*=flag;
}
const int _SIZE=5e4;
int n,m,len;
int a[_SIZE+5],sum[_SIZE+5],pos[_SIZE+5],R[_SIZE+5];
int ma[(_SIZE<<2)+5],mi[(_SIZE<<2)+5];
int ans[_SIZE+5];
struct QUERY{
int l,r,id;
}que[_SIZE+5];
bool cmp(QUERY x,QUERY y)
{
if (pos[x.l]!=pos[y.l]) return x.l<y.l;
return x.r<y.r;
}
int main()
{
//freopen("SP20644.in","r",stdin);
//freopen("SP20644.out","w",stdout);
//double st=clock();
read(n),read(m);++n;
len=sqrt(n);
for (int i=2;i<=n;i++)
{
read(a[i]);sum[i]=sum[i-1]+a[i];
pos[i]=(i-1)/len+1;
}
for (int i=1;i<=n;i++) sum[i]+=_SIZE;
//for (int i=1;i<=n;i++) printf("%d ",sum[i]); exit(0);
for (int i=1;i<=m;i++)
{
read(que[i].l);
read(que[i].r);
que[i].r++;
que[i].id=i;
}
for (int i=1;i<=len+1;i++) R[i]=min(n,i*len);
sort(que+1,que+m+1,cmp);
int l=0,r=0,lastblock=0,temp=0;
for (int i=1;i<=m;i++)
{
//printf("\n%d~%d ",que[i].l,que[i].r);
if (pos[que[i].l]==pos[que[i].r])
{
//printf("same block\n");
temp=0;
for (int j=que[i].l;j<=que[i].r;j++) ma[sum[j]]=0;
for (int j=que[i].r;j>=que[i].l;j--)
if (!ma[sum[j]]) ma[sum[j]]=j;
else temp=max(temp,ma[sum[j]]-j);
for (int j=que[i].l;j<=que[i].r;j++) ma[sum[j]]=0;
ans[que[i].id]=temp;
continue;
}
if (lastblock^pos[que[i].l])
{
//system("pause");
while (r>R[pos[que[i].l]])
{
// printf("%d ",r);
ma[sum[r]]=mi[sum[r]]=0;
r--;
}
while (l<R[pos[que[i].l]]+1)
{
ma[sum[l]]=mi[sum[l]]=0;
l++;
}
lastblock=pos[que[i].l];
r=l-1;
temp=0;
}
while (r<que[i].r)
{
++r;
if (!mi[sum[r]]) mi[sum[r]]=ma[sum[r]]=r;
else ma[sum[r]]=r,temp=max(temp,r-mi[sum[r]]);
}
int res=temp;
while (l>que[i].l)
{
--l;
if (!ma[sum[l]]) ma[sum[l]]=l;
else res=max(res,ma[sum[l]]-l);
}
while (l<R[pos[que[i].l]]+1)
{
if (ma[sum[l]]==l) ma[sum[l]]=0;
++l;
}
ans[que[i].id]=res;
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
//printf("%.0lfms\n",clock()-st);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步