abc250_e Prefix Equality 题解

发布时间 2023-04-16 23:45:10作者: luogu_wsy0704

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;
}