思路:在给的数组上建立主席树,改一下查询,查询L到R之间第一个大于等于k的数,再设一个set,把去掉的数放到set中,查询完主席树找set中最接近k的数,答案就是取上面两个数中的最小值
#include
#define eps 1e-14
#define pi acos(-1)
#define ll long long
#define RD T*(rand()*2-RAND_MAX)
#define Drand (long double)rand()/RAND_MAX
#define LINF 0x7f7f7f7f7f7f7f7f
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+100;
const long long mod=1e18;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;}
int tot=0;
int a[maxn],L[maxn*21],R[maxn*21],sum[maxn*21],T[maxn];
int n,m;
void build(int l,int r,int &rt)
{
rt=++tot;
sum[rt]=0;
if(l==r)return ;
int mid=(l+r)>>1;
build(l,mid,L[rt]);
build(mid+1,r,R[rt]);
}
void update(int l,int r,int &rt,int pre,int x)
{
rt=++tot;
L[rt]=L[pre];
R[rt]=R[pre];
sum[rt]=sum[pre]+1;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)update(l,mid,L[rt],L[pre],x);
else update(mid+1,r,R[rt],R[pre],x);
}
int query(int l,int r,int tl,int tr,int k)
{
if(l==r)return l>=k ? l : n+1 ;
int mid=(l+r)>>1;
int ans=n+1;
int resl=sum[ L[tr] ]-sum[ L[tl] ];
int resr=sum[ R[tr] ]-sum[ R[tl] ];
if(resr+resl==0)return n+1;
if(resl>0 && k<=mid){
ans=query(l,mid,L[tl],L[tr],k);
}
if(ans!=n+1)return ans;
if(resr>0){
ans=query(mid+1,r,R[tl],R[tr],k);
}
return ans;
}
inline int read()
{
int num = 0, flag = 1;
char c;
c = getchar();
while(!(('0' <= c && c <= '9') || c == '-')) c = getchar();
if(c == '-'){
flag = -1; c = getchar();
}
while('0' <= c && c <= '9'){
num = num * 10 + c - '0';
c = getchar();
}
return num * flag;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int t;
scanf("%d",&t);
while(t--){
n=read();
m=read();
tot=0;
// build(1,n+1,T[0]);
set<int>s;
for(int i=1;i<=n;i++){
a[i]=read();
update(1,n+1,T[i],T[i-1],a[i]);
}
update(1,n+1,T[n+1],T[n],n+1);
int ans=0;
while(m--){
int b;
b=read();
if(b==1){
int pos=read();
pos^=ans;
s.insert(a[pos]);
}
else{
int r=read(),k=read();
r^=ans;k^=ans;
ans=query(1,n+1,T[r],T[n+1],k);
auto ans1=s.lower_bound(k);
if(ans1!=s.end())ans=min(ans,*ans1);
printf("%d\n",ans);
}
}
}
return 0;
}