1 条题解
-
0
双线段树方法:
#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
- 上传者