abc250_e Prefix Equality 题解
Prefix Equality
题意
给定长度为 \(n\) 的整数序列 \(a\) 和 \(b\)。
对于每组询问,回答以下内容:
- 如果 \(a\) 的前 \(x_i\) 项数值构成的不重复集合与 \(b\) 的前 \(y_i\) 项相同,输出
Yes
,否则输出No
。
数据范围
- \(1 \leqslant x_i, y_i < n \leqslant 2 \times 10^5, 1 \leqslant q \leqslant 2 \times 10^5\)
- \(1 \leqslant a_i, b_i \leqslant 10^9\)
思路
两种做法:在线和离线,在线是莫队,不会。
可以发现,对于 \(1 \leqslant i \leqslant n\),\(a\) 的前 \(i\) 项与 \(b\) 的前 \(j\) 项构成的不重复集合相同,且这里的 \(j\) 必然构成了一段连续的区间。
那么就好办了,先预处理出每个 \(i\) 的合法答案区间,然后对于每组询问去判断一下即可。
随着 \(i\) 的增大,\(j\) 的区间不会往左移,可以用双指针。具体实现看代码。
复杂度
- 时间:\(O(n\log n)\)
- 空间:\(O(n)\)
Code
点击查看代码
#include <iostream>
#include <set>
using namespace std;
const int N = 2e5 + 10;
struct ANS {
int l, r;
} ans[N];
int n, a[N], b[N], x, y, q;
set<int> st, st2; // 用 set 维护 a 和 b 的前 i、j 项,刚好还能去个重
int main () {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
for (int i = 1, j = 1; i <= n; i++) {
if (st2.find(a[i]) != st2.end()) { // 当前处理的数已经出现过了,那么这个区间与上一个区间相同
ans[i] = ans[i - 1];
} else {
st2.insert(a[i]); // 记录
for (; j <= n && st2.find(b[j]) != st2.end(); j++) { // 不断查找,直到有一个数没在 a 的前 i 项中出现过
st.insert(b[j]); // 记录,去重
if (st.size() == st2.size()) { // 两个大小相同了,说明这个时候可以统计答案区间
if (!ans[i].l) { // 更新区间
ans[i] = {j, j};
} else {
ans[i].r = j;
}
}
}
}
}
for (cin >> q; q; q--) {
cin >> x >> y;
cout << (ans[x].l <= y && ans[x].r >= y ? "Yes\n" : "No\n"); // 回答询问
}
return 0;
}