题目大意
给出一个序列,有以下两种操作:
- 1 x 1~~x 1 x:将位置 x x x上的数删除。
- 2 l r 2~~l~~r 2 l r:若该区间内有两个相同的数输出 1 1 1否则输出 0 0 0。
解题思路
很好的一道题,之前在洛谷写过查询区间内是否有两数相同是用莫队维护的区间种类数,但是本题如果写莫队估计要 T L E TLE TLE,然后学到了这手很强的问题转化技巧:
对于区间内的每个数,我们只需要知道它右边离他最近相同数的在哪个位置,然后判断区间内的最小值是否在区间内。(或者等价的,查询每个数左边相同数的位置最大值是否在区间内)。那么这时删除一个数,只需要像双向链表那样删除就行,因此需要两个数组 L , R L,R L,R分别记录每个数最左边和最右边相邻的数,需要注意链表首尾节点的删除要特判一下,删除节点就单点更新其最右边的相同的数为无穷。
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
#define ENDL "\n"
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 5e5 + 10;
const int Mod = 1e9 + 7;
int n;
int a[maxn], L[maxn], R[maxn], pre[maxn * 2];
int tree[maxn << 2];
void build(int i, int l, int r) {
if (l == r) {
tree[i] = R[l];
return;
}
int mid = (l + r) >> 1, k = i << 1;
build(k, l, mid);
build(k | 1, mid + 1, r);
tree[i] = min(tree[k], tree[k | 1]);
}
void change(int i, int l, int r, int pos, int x) {
if (l == r) {
tree[i] = x;
return;
}
int mid = (l + r) >> 1, k = i << 1;
if (pos <= mid) change(k, l, mid, pos, x);
else change(k | 1, mid + 1, r, pos, x);
tree[i] = min(tree[k], tree[k | 1]);
}
int query(int i, int l, int r, int x, int y) {
if (l == x && r == y) return tree[i];
int mid = (l + r) >> 1, k = i << 1;
if (y <= mid) return query(k, l, mid, x, y);
else if (x > mid) return query(k | 1, mid + 1, r, x, y);
else return min(query(k, l, mid, x, mid), query(k | 1, mid + 1, r, mid + 1, y));
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int q, op, l, r;
cin >> n >> q;
memset(pre, 0x3f, sizeof pre);
for (int i = 1; i <= n; i++) {
cin >> a[i];
L[i] = pre[a[i]];
pre[a[i]] = i;
}
memset(pre, 0x3f, sizeof pre);
for (int i = n; i >= 1; i--) R[i] = pre[a[i]], pre[a[i]] = i;
//for (int i = 1; i <= n; i++) cout << L[i] << " "; cout << endl;
//for (int i = 1; i <= n; i++) cout << R[i] << " "; cout << endl;
build(1, 1, n);
while (q--) {
cin >> op;
if (op == 1) {
cin >> l;
if (L[l] == inf) {
if (R[l] != inf) {
L[R[l]] = inf;
}
} else {
if (R[l] == inf) {
R[L[l]] = inf;
change(1, 1, n, L[l], inf);
} else {
R[L[l]] = R[l];
L[R[l]] = L[l];
change(1, 1, n, L[l], R[l]);
}
}
L[l] = R[l] = inf;
change(1, 1, n, l, inf);
} else {
cin >> l >> r;
int cur = query(1, 1, n, l, r);
//cout << cur << " ";
if (cur <= r) cout << "1" << endl;
else cout << "0" << endl;
}
}
return 0;
}