## \[ 本题要求: 求 [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