题意
一个长度为n的排列a,(forall iin [1,n] ,1le a_i le n) , m次操作,每次操作:
- (1,pos),把 (a_{pos}) 变为(a_{pos} + 10000000)
- (2,r,k) ,找到最小的一个值x,使得(forall iin [1,r], x eq a_i, xge k)
数据范围:
(1le nle 100000,1le mle 100000,1le rle n,1le kle n)
分析
-
观察每个数的值域,都在([1,n]) 之间,而k的范围也在([1,n]) 之间,所以答案最终只会在([1,n+1]) 之间。
-
操作1会使一个数字(a_i)加1e7,而这个数已经远远超过n和k,所以也就代表着(a_i)从原序列中被删除了。
-
由第一条可以知道,每次查询的答案只会在[k,n+1]上,而序列中的数只会在[1,n](进行过1操作的直接删除,不再考虑)。所以我们可以每次查询序列中有没有出现在([k,n]) 的数,并且他们的下标是大于r的。如果之前删除过一个数(x),那么就把这个下标变成大于n就可以了, 这样对于(kle x) 的情况,(x) 所对应的下标都是大于(r) 的(也就是把x作为候选答案)
如何维护查询所需要的东西?权值线段树维护区间权值最大下标
- 对于操作1,直接让单点的下标变为n+1
- 对于操作2,找被区间[k,n]的包含的结点,对于这些结点,如果左节点的最大下标大于r,则递归左节点,否则看右结点,如果都没有,就返回n+1(代表答案候选为n+1)。而递归到终点时,看单点维护的下标是否大于r,如果大于,就返回单点的权值,否则返回n+1.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int inf = 0x3f3f3f3f;
int a[N],b[N];
struct SegTree{
int l,r,id;
}t[4*N];
int n,m;
void build(int p,int l,int r){
t[p].l = l;t[p].r = r;
if(l == r){
t[p].id = b[l];
return;
}
int mid = l + r >> 1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].id = max(t[p*2].id,t[p*2+1].id);
}
void change(int p,int x){
if(t[p].l == t[p].r && t[p].l == x){
t[p].id = n+1;return;//删除该数,将维护的下标变为n+1
}
int mid = t[p].l + t[p].r >> 1;
if(x <= mid)change(p*2,x);
else if(x > mid)change(p*2+1,x);
t[p].id = max(t[p*2].id,t[p*2+1].id);
}
int query(int p,int l,int r,int x){
if(t[p].l >= l && t[p].r <= r){//找到被[k,n]完全包含的结点
if(t[p].l == t[p].r){
if(t[p].id > x)
return t[p].l;
return n + 1;
}
if(t[p*2].id > x)return query(p*2,l,r,x);
if(t[p*2+1].id > x)return query(p*2+1,l,r,x);
return n + 1;
}
int mid = t[p].l + t[p].r >> 1;
int res = n+1;
if(mid >= l){
res = query(p*2,l,r,x);
}
if(mid < r){
res = min(res, query(p*2+1,l,r,x));
}
return res;
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)b[i] = 0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[a[i]] = i;//因为时排列,每个a[i]都不一样
}
build(1,1,n);
int res = 0;
while(m--){
int op,x,y;
scanf("%d%d",&op,&x);
if(op == 1){
x ^= res;
change(1,a[x]);
}
else{
scanf("%d",&y);x^=res;y^=res;
res = query(1,y,n,x);
printf("%d
",res);
}
}
}
return 0;
}