正题
题目链接:https://www.luogu.com.cn/problem/P5906
题目大意
nnn个数字,mmm个询问[l,r][l,r][l,r]中最远的相同数字对。
解题思路
我们考虑如何用莫队维护,对于一个询问[l,r][l,r][l,r],我们先按照lll的块排再按照rrr排,定义lll块的右端为midmidmid,那么我们可以先处理[mid,r][mid,r][mid,r]的范围,然后[l,mid][l,mid][l,mid]暴力处理,因为rrr是递增的,所以时间复杂度为O(nn)O(n\sqrt n)O(nn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
struct node{int l,r,id;
}q[N];
int n,m,T,answer,ans[N],fin[N],a[N],pos[N],b[N],st[N],last[N],cl[N];
bool cmp(node x,node y){if(pos[x.l]==pos[y.l])return x.r<y.r;return x.l<y.l;
}
int main()
{scanf("%d",&n);T=sqrt(n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[i]=(i-1)/T+1,b[i]=a[i];sort(b+1,b+1+n);int cnt=unique(b+1,b+1+n)-b-1;for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;scanf("%d",&m);for(int i=1;i<=m;i++)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;sort(q+1,q+1+m,cmp);cnt=0;int l=1,r=0;for(int i=1;i<=m;i++){if(pos[q[i].l]!=pos[q[i-1].l]){for(int j=1;j<=cnt;j++)last[cl[j]]=st[cl[j]]=0;cnt=answer=0;l=min(pos[q[i].l]*T,n);r=l-1;}if(pos[q[i].l]==pos[q[i].r]){int res=0;for(int j=q[i].l;j<=q[i].r;j++)fin[a[j]]=0;for(int j=q[i].l;j<=q[i].r;j++){if(fin[a[j]])res=max(res,j-fin[a[j]]);else fin[a[j]]=j;}ans[q[i].id]=res;continue;}while(r<q[i].r){r++;last[a[r]]=r;if(!st[a[r]])st[a[r]]=r,cl[++cnt]=a[r];answer=max(answer,r-st[a[r]]);}int pre=answer;while(l>q[i].l){l--;if(!last[a[l]])last[a[l]]=l;answer=max(answer,last[a[l]]-l);}ans[q[i].id]=answer;while(l<=min(pos[q[i].l]*T,n)){if(last[a[l]]==l)last[a[l]]=0;l++;}answer=pre;}for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}