回滚莫队也叫做不删除莫队,对于某些在莫队中的操作,不好统计删除操作是就可以回滚。
回滚的意思就是,先撤销对某个点的操作然后再增加回来(所以同理有不增加莫队)
如果块中的两点在同一个块上,那么暴力即可。这样每次操作的复杂度为根号n
如果不在同一个块中,那么需要将左端点置与块中的末端,右端点置于下一块的首端,可以知道对于同一个块中的右端点总是递增的
所以统计一个块右端点的复杂度为n,有根号n个块,那么总复杂度为n根号n
所以总体复杂度还是n根号n级别的。
贴一个洛谷P5906的AC代码
题意:给定一个序列,多次询问一段区间 [l,r],求区间中相同的数的最远间隔距离。
序列中两个元素的间隔距离指的是两个元素下标差的绝对值。
#include<bits/stdc++.h>
using namespace std;
struct node
{
long long l,r,num;
}t[2000005];
long long block;
const long long maxn=2000005;
long long zuo[2000005],you[2000005],b[maxn],c[maxn],a[maxn],use[maxn],da[maxn];
long long rr[maxn],zz[maxn];
bool cmp(node x,node y)
{
if(x.l/block!=y.l/block) return x.l/block<y.l/block;
else return x.r<y.r;
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
long long n;
cin>>n;
block=sqrt(n);
for(long long i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
//离散化
sort(b+1,b+n+1);
long long q=unique(b+1,b+n+1)-b-1;
// cout<<"q="<<endl;
for(long long i=1;i<=n;i++)
c[i]=lower_bound(b+1,b+q+1,a[i])-b;
// for(long long i=1;i<=n;i++)
// cout<<"c[i]="<<c[i]<<endl;
//代替数组
long long m;
cin>>m;
for(long long i=1;i<=m;i++)
{
cin>>t[i].l>>t[i].r;
t[i].num=i;
}
sort(t+1,t+1+m,cmp);
// for(long long i=1;i<=m;i++) cout<<t[i].l<<" "<<t[i].r<<endl;
long long ls,rs;//还是从1开始吧,否则麻烦特别多
// biao[c[ls]]++;
// rr[c[ls]]=ls;
// zz[c[ls]]=ls;
long long kuai=-1;
// fill(zuo,zuo+n+1,maxn);
// fill(you,you+n+1,0);
long long yuan=0;
for(long long i=1;i<=m;i++)
{
if(t[i].l/block==t[i].r/block)
{
long long ans=0;
for(long long j=t[i].l;j<=t[i].r;j++)
{
// use[c[j]]++;
if(use[c[j]]==0) use[c[j]]=j;
// you[c[j]]=j;
else ans=max(ans,j-use[c[j]]);
}
da[t[i].num]=ans;
for(long long j=t[i].l;j<=t[i].r;j++)
{
use[c[j]]=0;
}
}
else
{
long long ans=0;
if(t[i].l/block>kuai)
{
kuai=t[i].l/block;
yuan=0;
for(long long j=1;j<=n;j++) zz[c[j]]=rr[c[j]]=0;
long long lin=t[i].l/block*block+block;
ls=lin,rs=lin-1;
}
while(rs<t[i].r)
{
// if(rs>n) cerr<<"chao1"<<endl;
rs++;
rr[c[rs]]=rs;
if(zz[c[rs]]==0) zz[c[rs]]=rs;
else ans=max(ans,rs-zz[c[rs]]);
}
ans=max(yuan,ans);
yuan=ans;//这个临时变量很重要,之前因为这个的忽略调了无数次
ls=t[i].l/block*block+block;//重新弄
while(ls>t[i].l)
{
ls--;
// if(ls>n || ls<1) cerr<<"chao2"<<endl;
if(rr[c[ls]]==0) rr[c[ls]]=ls;
else ans=max(ans,rr[c[ls]]-ls);
// ls--;
}
da[t[i].num]=ans;
for(long long j=t[i].l;j<=t[i].l/block*block+block-1;j++)
if(rr[c[j]]==j) rr[c[j]]=0;
}
}
for(long long i=1;i<=m;i++)
printf("%d\n",da[i]);
}