块长调过很多次了……
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, a[N], b[N], ear[N], late[N];
int blk, tot, bel[N];
int ret[N], clean[N];
struct event{
int l, r, id;
bool operator < (const event &p) const {
if(bel[l] != bel[p.l])
return bel[l] < bel[p.l];
return r < p.r;
}
} q[N];
int baoli(int l, int r){
int lear[N] = {0}, res = 0;
// for(int i=l;i<=r;i++)
// ear[a[i]] = 0;
for(int i=l;i<=r;i++){
if(!lear[a[i]])
lear[a[i]] = i;
res = max(res, i - lear[a[i]]);
}
return res;
}
int main(){
scanf("%d", &n);
for(int i=1;i<=n;i++)
scanf("%d", &a[i]), b[i] = a[i];
sort(b + 1, b + 1 + n);
int len = unique(b + 1, b + 1 + n) - b - 1;
for(int i=1;i<=n;i++)
a[i] = lower_bound(b + 1, b + 1 + len, 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;
blk = 233;
for(int i=1;i<=n;i++)
bel[i] = (i - 1) / blk + 1;//分块基础
sort(q + 1, q + 1 + m);
int now = 1;//当前处理到第几个询问
for(int j=1;j<=bel[n];j++){//枚举每个块
int tmp = 0, br = min(n, j * blk);//br 块的右端点
int l = br + 1, r = l - 1, ans = 0;//l, r 左右指针,ans 当前答案
while(bel[q[now].l] == j){//左端点在同一块内一起处理
if(bel[q[now].l] == bel[q[now].r]){
ret[q[now].id] = baoli(q[now].l, q[now].r);
++now;
continue;
}
while(r < q[now].r){
++r;
late[a[r]] = r;
if(!ear[a[r]])
ear[a[r]] = r, clean[++tmp] = a[r];
ans = max(ans, r - ear[a[r]]);
}
int ansr = ans;//右端点单调递增,因此答案不用清空,左端点则需要清空
while(l > q[now].l){
--l;//不用更新 ear 数组,因为后面再也没有右端点右移的操作了,左端点自己就是 ear[a[l]]
if(!late[a[l]])
late[a[l]] = l;
ans = max(ans, late[a[l]] - l);
}
ret[q[now].id] = ans;//这个询问已经处理完了
while(l <= br){
if(late[a[l]] == l)//如果最开始的数在左边出现,直接清零即可,不用看后一次的位置
late[a[l]] = 0;//因为左端点最后会到块的右端点
l++;
}
++now, ans = ansr;//继承右端点的答案,这样就消除了左端点的影响
}
for(int i=1;i<=tmp;i++)
late[clean[i]] = ear[clean[i]] = 0;//下一个块到来时,这一块右端点的答案就需要被清空
}
for(int i=1;i<=m;i++)
printf("%d\n", ret[i]);
return 0;
}