基本参照第一篇题解。已经写了两天了。讨论区也都翻过了真的调不出来
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, block, last[N], num[N], a[N], br[N], ma[N], fir[N], clear[N], ANS[N];
struct node{
int l, r, id;
}q[N];
bool cmp(node x, node y){
if(x.l / block != y.l / block) return x.l / block < y.l / block;
return x.r < y.r;
}
void calc(int L, int R, int id){
int maxn = 0;
for(int i = L; i <= R; i++) last[a[i]] = 0;
for(int i = L; i <= R; i++){
if(!last[a[i]]) last[a[i]] = i;
maxn = max(maxn, i - last[a[i]]);
}
ANS[id] = maxn;
}
signed main(){
//回滚莫队:正常莫队+l回滚,并记录初始值
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]), num[i] = a[i];
sort(num + 1, num + n + 1);
int tot = unique(num + 1, num + n + 1) - num - 1;
for(int i = 1; i <= n; i++){
a[i] = lower_bound(num + 1, num + tot + 1, a[i]) - num;
}
//正常离散化()
scanf("%d", &m);
for(int i = 1; i <= m; i++){
scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;
}
block = sqrt(n); //块数。这里我直接用i / block表示i所属的块
sort(q + 1, q + m + 1, cmp);
for(int i = 1; i <= n; i++) //这个块的右端点
br[i / block] = i;
int l = 0, r = 0, ans = 0, cnt = 0;
//先移动r,并记录此时的状态,l挪至原位时则恢复
for(int i = 1, j = -1; i <= m; i++){ //第i个询问,第j个块
if(q[i].l / block > j){
for(int i = 1; i <= cnt; i++) ma[clear[i]] = 0, fir[clear[i]] = 0, clear[i] = 0;
cnt = 0;
j = q[i].l / block;
l = br[j] + 1; r = l - 1;
}
if(q[i].l / block == q[i].r / block){ //在同个块,暴力
calc(q[i].l, q[i].r, q[i].id);
}
else{
while(r < q[i].r){
r++;
if(!fir[a[r]]) fir[a[r]] = r;
clear[++cnt] = a[r];
ma[a[r]] = r;
ans = max(ans, ma[a[r]] - fir[a[r]]);
}
int tp = ans; //记录只考虑右边区间的ans
// printf("kk%d\n", tp);
while(l > q[i].l){
l--;
if(ma[a[l]]) ans = max(ma[a[l]] - l, ans);
else ma[a[l]] = l;
}
// for(int i = 1; i <= 4; i++) printf("kkdy%d ", ma[i]);
// printf("\n");
// printf("kkdy%d %d %d %d\n", i, j, l, r);
ANS[q[i].id] = ans;
ans = tp;
while(l <= br[j]){
if(ma[a[l]] == l) ma[a[l]] = 0;
l++;
}
}
}
for(int i = 1; i <= m; i++) printf("%d\n", ANS[i]);
return 0;
}