题目连接:https://ac.nowcoder.com/acm/contest/9983/E
分析
我们用线段树维护一个数组 chushi[i] 表示 i 位置上的数在 i 位置以前第一个出现的位置。
判断 L 和 R 区间内是否出现重复的数,我们只要看 chushi 数组在该区间内的最大值 x ,若 x >= L,则说明有重复的数。
注意,我们拿走一个位置上的数后,还要修改和这个位置上的数相等的下一个数的 chushi 数组的值。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
#define ll long long
int chushi[maxn], sum[maxn * 4],pre[maxn],after[maxn],a[maxn];
void pushup(int rt)
{
sum[rt] = max(sum[2 * rt], sum[2 * rt + 1]);
}
void build(int l, int r, int rt)
{
if (l == r)
{
sum[rt] = chushi[l];
return;
}
int mid = (l + r) / 2;
build(l, mid, 2 * rt);
build(mid + 1, r, 2 * rt + 1);
pushup(rt);
}
int qurry(int x, int y, int l, int r, int rt)
{
if (x <= l && y >= r)
{
return sum[rt];
}
int mid = (l + r) / 2;
int ret = 0;
int ret1 = 0;
if (x <= mid) ret = max(ret, qurry(x, y, l, mid, 2 * rt));
if (y > mid) ret1 = max(ret1, qurry(x, y, mid + 1, r, 2 * rt + 1));
return max(ret1, ret);
}
void update(int x, int c, int l, int r, int rt)
{
if (l == r)
{
sum[rt] = c;
return;
}
int mid = (l + r) / 2;
if (x <= mid)update(x, c, l, mid, 2 * rt);
else update(x, c, mid + 1, r, 2 * rt + 1);
pushup(rt);
}
int main()
{
int n, q;
scanf("%d%d",&n,&q);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
chushi[i] = pre[a[i]];
after[pre[a[i]]] = i;
pre[a[i]] = i;
}
build(1, n, 1);
while (q--)
{
int ch;
int x, y;
scanf("%d", &ch);
if(ch==2)
{
scanf("%d%d",&x,&y);
printf("%d\n", qurry(x, y, 1, n, 1)>=x?1:0);
}
else
{
scanf("%d",&x);
after[chushi[x]] = after[x];
chushi[after[x]] = chushi[x];
chushi[x] = 0;
int i = after[x];
after[x] = 0;
update(x, 0, 1, n, 1);
update(i, chushi[i], 1, n, 1);
}
}
}