首先我们观察到a数组是一个排列,并且k也是在1-n之间,说明我们的答案一定是不大于n+1
又因为第一种操作直接加了1e7,因此我们相当于将这个数剔除,也就是将这个数作为可选范围内。
我们要求的是大于k的数,并且不能与1-r之间的答案相同。
那么我们就要直接从线段树上k-n找答案。
因此我们只需要维护一个区间下标最大值即可,只要区间每个数对应的坐标大于给定的r,那么就存在答案
对于第一种操作,只需要修改当前位置的坐标为n+1,表示这个点可以作为可选范围。
如果1-n没有答案,那么答案就是n+1
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int n,m; int a[N]; int b[N]; struct node{ int l,r; int cnt; }tr[N<<2]; void pushup(int u){ tr[u].cnt=max(tr[u<<1].cnt,tr[u<<1|1].cnt); } void build(int u,int l,int r){ if(l==r){ tr[u]={l,l,b[l]}; } else{ tr[u]={l,r,0}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } set<int> s; void modify(int u,int l){ if(tr[u].l==tr[u].r){ tr[u].cnt=n+1; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l); else modify(u<<1|1,l); pushup(u); } int query(int u,int l,int r,int x){ if(tr[u].l >=l && tr[u].r <= r){ if(tr[u].l == tr[u].r){ if(tr[u].cnt>x) return tr[u].l; return n+1; } if(tr[u<<1].cnt>x)return query(u<<1,l,r,x); if(tr[u<<1|1].cnt>x)return query(u<<1|1,l,r,x); return n+1; } int mid=tr[u].l+tr[u].r >> 1; int res=n+1; if(mid>=l){ res=query(u<<1,l,r,x); } if(mid < r){ res=min(res,query(u<<1|1,l,r,x)); } return res; } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n>>m; int i; for(i=1;i<=n;i++) b[i]=0; for(i=1;i<=n;i++){ cin>>a[i]; b[a[i]]=i; } build(1,1,n); int last=0; while(m--){ int opt,x,y; cin>>opt; if(opt==1){ cin>>x; x^=last; modify(1,a[x]); } else{ cin>>x>>y; x^=last,y^=last; cout<<(last=query(1,y,n,x))<<endl; } } } }