题目链接
题意:略
思路:对于操作1,a[i]修改后原a[i]的值可以成为以后询问时的答案,压入set中;操作2在区间[r+1,n]上找大于等于K的值,因为可能是修改操作的值,从set中找到大于等于k的值与主席树中区间[r+1,n]中大于等于k的值取小的即可;利用set避免在主席树上做修改,即使主席树上查到的值非法(值被修改了)在set中仍会找到合法值,并不冲突。
代码:
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+1000;
struct node
{
int l,r,num;
}tree[maxn*40];
int n;
int root[maxn],tot;
int a[maxn];
int sz=maxn;
void update(int l,int r,int &x,int y,int pos)
{
tree[++tot]=tree[y];
x=tot;
tree[x].num++;
if(l==r) return ;
int m=(l+r)>>1;
if(pos<=m) update(l,m,tree[x].l,tree[y].l,pos);
else update(m+1,r,tree[x].r,tree[y].r,pos);
}
int query(int l,int r,int x,int y,int L,int R)
{
if(l==r){
if(tree[y].num-tree[x].num>0)//该点是否有值
return l;
else return n+1;//n+1一定合法
}
int m=(l+r)>>1;
int tmp=tree[tree[y].l].num-tree[tree[x].l].num;
int ans=n+1;
if(L<=m&&tmp>0) ans=min(ans,query(l,m,tree[x].l,tree[y].l,L,R));//tmp>0 左区间可能有解
if(R>m&&ans==n+1) ans=min(ans,query(m+1,r,tree[x].r,tree[y].r,L,R));//左区间无解找右区间
return ans;
}
int main()
{
int kase;
scanf("%d",&kase);
while(kase--)
{
set s;
tot=0;
int q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++) update(1,sz,root[i],root[i-1],a[i]);
int lastans=0;
while(q--)
{
int op;
scanf("%d",&op);
if(op==1){
int pos;
scanf("%d",&pos);
pos^=lastans;
s.insert(a[pos]);
}else{
int r,k;
scanf("%d%d",&r,&k);
r^=lastans;k^=lastans;
int ans=1e9;
if(s.lower_bound(k)!=s.end()){
ans=*s.lower_bound(k);
}
ans=min(ans,query(1,sz,root[r],root[n],k,n));
printf("%d\n",ans);
lastans=ans;
}
}
}
return 0;
}