## \[ 本题要求: 求 [l,r] 内最长连续无重子序列(下称LCRS) \]
如何解决
st[i] 记录以i结尾的LCRS的起点)last[i] 记录 i 在 a[] 中上次出现的位置
p.s. st[]在任何一个序列中都是单调不上升的,有兴趣的读者可以自己推推看- 怎么做
- 处理\(last[i]\);
- 维护\(st[i]\)转移:$ st[i] = max(st[i-1],last[a[i]]+1) $
- 所以\(f[i][0]=i-st[i]+1\)
- 所以可以预处理\(RMQ\)
- 对每一次询问的\(L,R寻找其pos(pos的左侧所有的st[i]<l,右侧都 >=l)\)
- 所以 $ answer = max(pos-l,RMQ(pos,r))$
p.s. 因为st是单调的,所以可以用二分找pos
#include <bits/stdc++.h> using namespace std; const int maxn = 2 * 1e6 + 5; const int adnu = 1e6 + 5; const int logn = 50; int n, m; int last[maxn], st[maxn], a[maxn], len[maxn]; int f[maxn][logn], lg[maxn]; void RMQ() { lg[0] = -1; for (int i = 1; i <= n; i++) { f[i][0] = len[i]; lg[i] = lg[i / 2] + 1; } for (int j = 1; j <= lg[n] + 1; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) { f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); } } } int bis(int l, int r) { if(l == r) return l; int x = l, y = r; while (x <= y) { int mid = x + (y-x) / 2; if (st[mid] < l) x = mid + 1; else y = mid - 1; } return x; } int rmq(int x, int y) { return max(f[x][lg[y - x + 1]], f[y - (1 << lg[y - x + 1]) + 1][lg[y - x + 1]]); } void solve(int l, int r) { if (st[r] <= l) printf("%d\n", r - l + 1); else if (st[l] == l) printf("%d\n", rmq(l, r)); else { int pos = bis(l, r); printf("%d\n", max(pos - l, rmq(pos, r))); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i] += adnu; st[i] = max(st[i - 1], last[a[i]] + 1); len[i] = i - st[i] + 1; last[a[i]] = i; } RMQ(); for (int i = 1; i <= m; i++) { int l,r; scanf("%d%d", &l, &r); l++; r++; solve(l, r); } return 0; }
来源:https://www.cnblogs.com/yangxuejian/p/11109297.html