点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,len;//len代表块大小
int a[N],b[N];
//a是离散化后的数组
//b是元素属于的块
int R[N];//每个块的右端
int ans[N];//答案
int st[N],ed[N],ed2[N];
//st代表元素第一次出现的位置
//ed代表元素出现的最后一次的位置
//ed2代表每组询问的公共起点前的一段中,元素出现的最后一个位置
struct node{int id,x;}tmp[N];
struct query{int l,r,id;}q[N];
bool cmp1(node x,node y){return x.x<y.x;}
//如果左端点块相同,优先按照右端点排序,否则按照左端点所在块进行排序
bool cmp2(query x,query y){return b[x.l]==b[y.l]?x.r<y.r:b[x.l]<b[y.l];}
void data()
{
cin >>n;
len=sqrt(n);
for(int i=1;i<=n;i++)
{
cin >>tmp[i].x;
tmp[i].id=i;
b[i]=(i-1)/len+1;
}
for(int i=1;i<=n;i++) R[i]=(i==b[n])?n:len*i;
cin >>m;
for(int i=1;i<=m;i++)
{
cin >>q[i].l>>q[i].r;
q[i].id=i;
}
sort(q+1,q+m+1,cmp2);
}
void tmp_()//离散化
{
sort(tmp+1,tmp+n+1,cmp1);
int pre=-1,cnt=0;
for(int i=1;i<=n;i++)
{
if(tmp[i].x!=pre) cnt++;
a[tmp[i].id]=cnt;
pre=tmp[i].x;
}
}
void work()
{
int block=0,tmp1=0,l=0,r=0;
//block代表上次询问的左端点属于哪个块
//如果块一样就使用上次留下来的进程
//否则就重新计算
//tmp1代表公共L到上一次询问的R得到的答案
//l公共L
//r上一次询问的R
for(int i=1;i<=m;i++)
{
if(b[q[i].l]==b[q[i].r])//如果同属一个块,直接暴力求解
{
tmp1=0;
for(int j=q[i].l;j<=q[i].r;j++) st[a[j]]=0;
for(int j=q[i].l;j<=q[i].r;j++)
{
if(!st[a[j]]) st[a[j]]=j;
tmp1=max(tmp1,j-st[a[j]]);
}
for(int j=q[i].l;j<=q[i].r;j++) st[a[j]]=0;
ans[q[i].id]=tmp1;
continue;
}
int now=b[q[i].l];//记录左端点所在块
if(block!=now)//左端点所在块发生改变
{
tmp1=0;
for(int j=l;j<=r;j++) st[a[j]]=ed[a[j]]=0;//直接清空
l=R[now];//先在now所在块的下一个块进行计算,最后再处理不完整的块
r=l-1;
block=now;//更新所在块
}
while(r<q[i].r)
{
r++;
if(!st[a[r]]) st[a[r]]=r;//元素第一次出现位置
ed[a[r]]=r;//更新最后一次出现位置
tmp1=max(tmp1,r-st[a[r]]);
}
int p=l,tmp2=0;//开始处理不完整的块
while(q[i].l<p)
{
p--;
if(!ed2[a[p]]) ed2[a[p]]=p;//从后往前更新
tmp2=max(tmp2,max(ed[a[p]],ed2[a[p]])-p);//p最后出现的位置可能存在公共L的右端所以要取max
}
while(p<l)
{
ed2[a[p]]=0;
p++;
}
ans[q[i].id]=max(tmp2,tmp1);
}
}
signed main()
{
data();
tmp_();
work();
for(int i=1;i<=m;i++) cout <<ans[i]<<'\n';
return 0;
}