原题
题意:有两种操作
1 x 表示删去x位置的数
2 l r 表示查询l到r区间是否存在两个数相同。
题解:
w
[
i
]
表
示
i
前
面
与
a
[
i
]
相
同
的
数
a
[
j
]
且
下
标
最
大
的
j
。
w[i]表示i前面与a[i]相同的数a[j]且下标最大的j。
w[i]表示i前面与a[i]相同的数a[j]且下标最大的j。
为什么要下标最大的?
因为比如1 4 3 4 4 5
查询区间4到5 存在4相同。那么查询区间2到5 一样会存在4相同,只要记录离自己最近的就可以
r
w
[
i
]
表
示
i
后
面
与
a
[
i
]
相
同
的
数
a
[
j
]
且
下
标
最
小
的
j
。
rw[i]表示i后面与a[i]相同的数a[j]且下标最小的j。
rw[i]表示i后面与a[i]相同的数a[j]且下标最小的j。
存rw是为了后面修改某个点需要用到,因为修改这个点会影响到后面的那个点。
求w和rw的过程可以用set维护每个值出现的位置。然后正向和反向求一次就可以了
如果不存在这样的数那么 w [ i ] = 0 , r w [ i ] = n + 1 w[i]=0 , rw[i]=n+1 w[i]=0,rw[i]=n+1
然后对w[i]建一个最大值线段树
查询时:若区间l到r的最大值大于等于l,说明存在。
修改时:
u
p
d
a
t
e
(
1
,
l
,
0
)
;
i
f
(
r
w
[
l
]
<
=
n
)
u
p
d
a
t
e
(
1
,
r
w
[
l
]
,
w
[
l
]
)
;
w
[
r
w
[
l
]
]
=
w
[
l
]
;
r
w
[
w
[
l
]
]
=
r
w
[
l
]
;
w
[
l
]
=
0
;
r
w
[
l
]
=
n
+
1
;
update(1,l,0);\\ if(rw[l]<=n)update(1,rw[l],w[l]);\\ w[rw[l]]=w[l];\\ rw[w[l]]=rw[l];\\ w[l]=0;\\ rw[l]=n+1;\\
update(1,l,0);if(rw[l]<=n)update(1,rw[l],w[l]);w[rw[l]]=w[l];rw[w[l]]=rw[l];w[l]=0;rw[l]=n+1;
跟链表差不多。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
typedef long long ll;
const int N=5e5+10,G=1e6+10;
int w[N],n,q,k;
struct node
{
int l,r;
int v;
} tr[4*N];
inline void pushup(int u)
{
tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]= {l,l,w[l]};
return ;
}
tr[u]= {l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
int mid=tr[u].l+tr[u].r>>1;
int v=0;
if(l<=mid)v=query(u<<1,l,r);
if(r>mid)v=max(query(u<<1|1,l,r),v);
return v;
}
void update(int u,int x,int v)
{
if(tr[u].l==x&&tr[u].r==x)
{
tr[u].v=v;
}
else
{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)update(u<<1,x,v);
else update(u<<1|1,x,v);
pushup(u);
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(s[a[i]].size())w[i]=*(--s[a[i]].end());
s[a[i]].insert(i);
}
for(int i=n; i>=1; i--)
{
rw[i]=n+1;
if(suf[a[i]].size())rw[i]=*(suf[a[i]].begin());
suf[a[i]].insert(i);
}
build(1,1,n);
while(q--)
{
int op,l,r;
scanf("%d%d",&op,&l);
if(op==1)
{
update(1,l,0);
if(rw[l]<=n)update(1,rw[l],w[l]);
w[rw[l]]=w[l];
rw[w[l]]=rw[l];
w[l]=0;
rw[l]=n+1;
}
else
{
scanf("%d",&r);
if(query(1,l,r)>=l)cout<<1<<'\n';
else cout<<0<<'\n';
}
}
return 0;
}
/*
5 5
1 2 3 4 5
1 1
*/