QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: Lynn_Sue

Posted at: 2026-07-16 08:47:12

Last updated: 2026-07-17 16:01:55

Back to Problem

一个简单的单根号在线做法

后续。

怎么感觉所有人都写了离线,还写的很复杂(

这个题完全是可以在线的,而且非常好写。复杂度 $O(n\sqrt{n}+q\sqrt{n})$。$n$ 是序列长度,$q$ 是询问数。

如果 $l$ 固定的话显然是好做的。直接向右推 $r$ 即可。$r$ 固定同理。

那这个题 $l$ 不固定怎么办,考虑选取 $\sqrt{n}$ 个点,向左向右推,求出这些区间的答案。显然时空复杂度均为 $O(n\sqrt{n})$。

然后我们考虑查询。对于一个区间 $l,r$,设 $l'$ 为 $l$ 右边第一个被选取的点,$r'$ 为 $r$ 左边第一个被选取的点,$[l,r']$ 和 $[l',r]$ 的答案可以 $O(1)$ 求出,剩下的就是 $[l,l')$ 和 $(r',r]$ 两端区间之间的贡献,把 $[l,l')$ 的所有数丢桶里,扫 $(r',r]$ 查即可。因为这两段区间长度都是 $O(\sqrt{n})$,所以单次查询复杂度为 $O(\sqrt{n})$。

代码出奇地好写。

#include<bits/stdc++.h>
#define F(i, a, b) for (int i = a; i <= b; i++)
using namespace std;
int n, m, q, a[100005], f[320][100005], b[100005];
int kc, ks, L[505], R[505], B[100005];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin >> n >> m;
    F(i, 1, n) cin >> a[i];
    kc = sqrt(n), ks = (n + kc - 1) / kc;
    F(i, 1, ks){
        L[i] = R[i - 1] + 1, R[i] = i == ks ? n : L[i] + kc - 1;
        F(j, L[i], R[i]) B[j] = i;
        F(j, L[i], n){
            if (!b[a[j]]) b[a[j]] = j;
            f[i][j] = max(f[i][j - 1], j - b[a[j]]);
        }
        F(j, 1, m) b[j] = 0;
        b[a[L[i]]]++;
        for (int j = L[i] - 1; j; j--){
            if (!b[a[j]]) b[a[j]] = j;
            f[i][j] = max(f[i][j + 1], b[a[j]] - j);
        }
        F(j, 1, m) b[j] = 0;
    }
    cin >> q;
    while (q--){
        int l, r, ans = 0;
        cin >> l >> r;
        if (B[l] == B[r]){
            F(i, l, r){
                if (!b[a[i]]) b[a[i]] = i;
                ans = max(ans, i - b[a[i]]);
            }
            F(i, l, r) b[a[i]] = 0;
        }else{
            ans = max(f[B[l] + 1][r], f[B[r]][l]);
            F(i, l, R[B[l]]) if (!b[a[i]]) b[a[i]] = i;
            F(i, L[B[r]], r) if (b[a[i]]) ans = max(ans, i - b[a[i]]);
            F(i, l, R[B[l]]) b[a[i]] = 0;
        }
        cout << ans << "\n";
    }
    return 0;
}

Comments

No comments yet.