离散化 + dp + ST 表

参考楼上大佬的题解,总结出下面的思路

r[i]:以 i 作为左端点时,其右端点的位置. 则以 i 为起点时,目标序列的最大长度为 r[i] - i + 1
r[i] 具有非减性质,这为二分提供了前提条件

对于区间[L,R],求其内部最长"好序列"的长度时,区间内每个点都有可能是“最长好序列”的左端点
所以有两种情况:(1)存在 r[i] > R 的左端点  (2)不存在 r[i] > R 的左端点

对于(1):
r[i] 大于 R 的左端点中,我们只需要考虑它们中最左边的那个(考虑r[i]的非减性,可用二分),得到 ans1
r[i] <= R 的左端点中,只有 r[i] - i + 1 最大的是我们需要的(预处理好,用ST来找) ,得到 ans2
答案为 max(ans1,ans2)

对于(2):
只有 r[i] <= R 的左端点,我们用 ST 表 求出它们中 r[i] - i + 1 最大的,即是答案

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5+10;

vector<int>V;
int log_2[N];
int f[N][20];
int a[N],r[N],cnt[N];
int n,m;

void ST(){
    log_2[1]=0;
    log_2[2]=1;
    for(int i=3;i<=n;i++) log_2[i]=log_2[i/2]+1;

    int k=log_2[n];
    for(int j=1;j<=k;j++)
      for(int i=1;i-1+(1<<j)<=n;i++)
         f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

int query(int l,int rr){
    int k=log_2[rr-l+1];
    int x=rr+1-(1<<k);
    return max(f[l][k],f[x][k]);
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],V.push_back(a[i]);
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    for(int i=1;i<=n;i++) a[i]=lower_bound(V.begin(),V.end(),a[i])-V.begin()+1;

    for(int i=1,j=1;i<=n;i++){
        while(j<=n&&cnt[a[j]]<1) {
            cnt[a[j]]++;  // cnt数组下标:a[j] 可能为负数,所以提前离散化搞一下数组a
            j++;
        }
        r[i]=j-1;
        cnt[a[i]]--;
    }

    for(int i=1;i<=n;i++) f[i][0]=r[i]-i+1;
    ST();

    int L,R;
    while(m--){
        cin>>L>>R;
        L++,R++;
        int ans=0;
        int j=upper_bound(r+L,r+R+1,R)-r;
        if(j<=R) {
            ans=R-j+1;
            if(j-1>=L) ans=max(ans,query(L,j-1));
        }
        else ans=query(L,R);
        cout<<ans<<endl;
    }
    return 0;
}