1 条题解

  • 0
    @ 2025-6-2 17:40:08

    双线段树方法:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 200000 + 5;
    const long long INFLL = (long long)4e18;
    
    // 全局变量
    int N, M;
    int a[MAXN];
    int lastPos[2000005];    // 记录上次出现位置(用偏移以支持负数)
    int farR[MAXN];          // farR[i] = 从 i 出发最长无重复子段结束下标
    int dpv[MAXN];           // dpv[i] = farR[i] - i + 1
    
    // 查询结构1:用来找区间 [L,R] 中最小下标 i 使得 farR[i] >= R
    // 每个节点存该区间内的最大 farR
    int st1[MAXN * 4];
    
    // 查询结构2:在线插入 dpv[i] 并取区间最大
    int st2[MAXN * 4];
    
    // 合并 st1 节点(区间最大)
    void pull1(int o) {
        st1[o] = max(st1[o<<1], st1[o<<1|1]);
    }
    // 合并 st2 节点(区间最大)
    void pull2(int o) {
        st2[o] = max(st2[o<<1], st2[o<<1|1]);
    }
    
    // 建立 st1(存 farR),st2 初始全为 -INF
    void build(int o, int l, int r) {
        if (l == r) {
            st1[o] = farR[l];
            st2[o] = -1000000000; // 负无穷
            return;
        }
        int m = (l + r) >> 1;
        build(o<<1, l, m);
        build(o<<1|1, m+1, r);
        pull1(o);
        pull2(o);
    }
    
    // st2 单点更新:把下标 p 的值设为 v
    void upd2(int o, int l, int r, int p, int v) {
        if (l == r) {
            st2[o] = v;
            return;
        }
        int m = (l + r) >> 1;
        if (p <= m) upd2(o<<1, l, m, p, v);
        else        upd2(o<<1|1, m+1, r, p, v);
        pull2(o);
    }
    
    // st2 区间查询最大
    int query2(int o, int l, int r, int ql, int qr) {
        if (ql > r || qr < l) return -1000000000;
        if (ql <= l && r <= qr) return st2[o];
        int m = (l + r) >> 1;
        int res = -1000000000;
        if (ql <= m) res = max(res, query2(o<<1, l, m, ql, qr));
        if (qr > m ) res = max(res, query2(o<<1|1, m+1, r, ql, qr));
        return res;
    }
    
    // st1 查询:找区间 [ql,qr] 中第一个下标 i 使 st1[i]>=v,否则返回 0
    int findFirst(int o, int l, int r, int ql, int qr, int v) {
        if (ql > r || qr < l || st1[o] < v) return 0; 
        if (l == r) return l;
        int m = (l + r) >> 1;
        int res = findFirst(o<<1, l, m, ql, qr, v);
        if (res) return res;
        return findFirst(o<<1|1, m+1, r, ql, qr, v);
    }
    
    // 主程序
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        cin >> N >> M;
        for (int i = 1; i <= N; i++) {
            cin >> a[i];
        }
    
        // 初始化 lastPos 为 0(表示未出现)
        memset(lastPos, 0, sizeof(lastPos));
    
        // 预处理 farR[i]:用双指针扫描
        int r = 1;
        for (int i = 1; i <= N; i++) {
            while (r <= N) {
                int val = a[r] + 1000000; 
                if (lastPos[val] >= i) break;
                lastPos[val] = r;
                r++;
            }
            farR[i] = r - 1;
            // 把 i 这个位置“移出窗口”:还原上次位置
            int vi = a[i] + 1000000;
            if (lastPos[vi] == i) lastPos[vi] = 0;
        }
    
        // 计算 dpv[i] = farR[i] - i + 1
        for (int i = 1; i <= N; i++) {
            dpv[i] = farR[i] - i + 1;
        }
    
        // 建立 st1/st2
        build(1, 1, N);
    
        // 离线查询:将所有 i 按 farR[i] 升序打包
        vector<pair<int,int>> order;
        order.reserve(N);
        for (int i = 1; i <= N; i++) {
            order.emplace_back(farR[i], i);
        }
        sort(order.begin(), order.end());
    
        // 读取查询,将 (L,R,idx) 存储
        struct Q { int L, R, id; };
        vector<Q> qs(M);
        for (int i = 0; i < M; i++) {
            cin >> qs[i].L >> qs[i].R;
            qs[i].L++; qs[i].R++; 
            qs[i].id = i;
        }
        // 按 R 升序排序
        sort(qs.begin(), qs.end(), [](const Q &a, const Q &b) {
            return a.R < b.R;
        });
    
        vector<int> ans(M);
        int ptr = 0;
        // 对每个查询按 R 递增处理
        for (auto &q: qs) {
            int L = q.L, Rq = q.R;
            // 把所有 farR[i] < Rq 的 i 插入 st2
            while (ptr < N && order[ptr].first < Rq) {
                int idx = order[ptr].second;
                upd2(1, 1, N, idx, dpv[idx]);
                ptr++;
            }
            // cand2 = max dpv[i] for i in [L, Rq] 且 farR[i] < Rq 已插入
            int cand2 = query2(1, 1, N, L, Rq);
            // cand1: 找 i in [L,Rq] 且 farR[i] >= Rq 的最小 i
            int idx = findFirst(1, 1, N, L, Rq, Rq);
            int cand1 = 0;
            if (idx) {
                cand1 = Rq - idx + 1;
            }
            ans[q.id] = max(cand1, cand2);
        }
    
        // 输出答案按原顺序
        for (int i = 0; i < M; i++) {
            cout << ans[i] << "\n";
        }
        return 0;
    }
    
    
    • 1

    信息

    ID
    999
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者