专栏文章
区间最长连续不重复子序列
题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miodvyk6
- 此快照首次捕获于
- 2025/12/02 17:36 3 个月前
- 此快照最后确认于
- 2025/12/02 17:36 3 个月前
弱化版
给定一个长度为 的序列 .
求 满足 互不相同。你需要最大化 并输出 。
如果有多个解输出其中 最小的那个。
弱化版题解
弱化版有多种解法,如二分答案长度,双指针,可以在 甚至 的时间复杂度内解决。
二分答案写法:二分一个长度 ,每次 的检查这个 是否合法。容易发现 有单调性。时间复杂度
双指针写法:每次 增加 ,并将 移动至最左边的合法的位置。容易发现 单调不降,时间复杂度 。
使用弱化版的 的做法可以通过强化版 的数据,使用弱化版 的做法可以通过强化版 的数据。
强化版
强化版在线做法
设 表示以 左端点,能取得的最右端点。并多维护一个 表示以 为左端点能取到的最长长度。
我们记录每一位的前驱, 表示 以前最大的 且 ,这是可以 求解的。
对于每一个 ,我们现在知道了 的所有 值,我需要找个一个最大的 满足 。因为左端点为定的 数组有单调性,所以可以二分。最后 。
这时候,使用第一个线段树或 st 表维护区间内 的最大值。
注意到 数组是非严格单调递增的。
证明: 数组是非严格单调递增的。若 ,那么发现区间 且 在区间 没有重复的元素。那么此时 最大可以取到 而非原本的 。证毕。
对于每一次询问 ,我们需要找到最左边的 满足 ,那么 区间内的贡献最大也是在位置 时,此时贡献为 。
我们再求出 在区间 的最大值即可。
这时候,使用第二个线段树或 st 表维护区间内 的最大值。
CPP#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
#define low_bit(x) ((x)&-(x))
//#define min(a,b) ((a)<(b)?(a):(b))
//#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
using ll = long long;
const int N = 2e5 + 5, M = 1e5 + 5;
int n, q, a[N];
int f[N], g[N], pre[N], d[M];
int t1[N << 2], t2[N << 2];
// zt = 1, 2 分别表示 g, pre
void push_up(int num, int zt){
if(zt == 1) t1[num] = max(t1[num << 1], t1[num << 1 | 1]);
if(zt == 2) t2[num] = max(t2[num << 1], t2[num << 1 | 1]);
}
void build(int num, int l, int r, int zt){
if(l == r){
if(zt == 1) t1[num] = g[l];
if(zt == 2) t2[num] = pre[l];
return;
}
int mid = (l + r) >> 1;
build(num << 1, l, mid, zt);
build(num << 1 | 1, mid + 1, r, zt);
push_up(num, zt);
}
int qry(int num, int l, int r, int L, int R, int zt){
if(l > R || r < L) return 0;
if(L <= l && r <= R){
if(zt == 1) return t1[num];
return t2[num];
}
int mid = (l + r) >> 1;
return max(qry(num << 1, l, mid, L, R, zt), qry(num << 1 | 1, mid + 1, r, L, R, zt));
}
bool check(int l, int x){// 需要 pre 在 [l, x] 的最大值 < l
return qry(1, 1, n, l, x, 2) < l;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
// freopen("015.in", "r", stdin);
// freopen("015.out", "w", stdout);
cin>>n;
for(int i = 1;i <= n;i++) cin>>a[i];
for(int i = 1;i <= n;i++){
pre[i] = d[a[i]];
d[a[i]] = i;
}
build(1, 1, n, 2);
for(int i = n;i >= 1;i--){
int l = i + 1, r = n, ans = i;
while(l <= r){
int mid = (l + r) >> 1;
if(check(i, mid)) l = mid + 1, ans = mid;
else r = mid - 1;
}
f[i] = ans;
g[i] = ans - i + 1;
}
build(1, 1, n, 1);
cin>>q;
while(q--){
int x, y; cin>>x>>y;
assert(1 <= x && x <= n && 1 <= y && y <= n);
int l = x, r = y, p = y + 1;
while(l <= r){
int mid = (l + r) >> 1;
if(f[mid] > y) r = mid - 1, p = mid;
else l = mid + 1;
}
int ans = 0;
if(p != y + 1){
ans = y - p + 1;
if(p == x){
cout<<ans<<'\n';
continue;
}
}
cout<<max(qry(1, 1, n, x, p - 1, 1), ans)<<'\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...