回滚莫队||不删除莫队

回滚莫队也叫做不删除莫队,对于某些在莫队中的操作,不好统计删除操作是就可以回滚。

回滚的意思就是,先撤销对某个点的操作然后再增加回来(所以同理有不增加莫队)

如果块中的两点在同一个块上,那么暴力即可。这样每次操作的复杂度为根号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]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值