2019CCPC网络赛 1002 HDU 6703(权值线段树)
思路:用权值线段树存题目给的数据后,2操作就是求权值线段树中大于等于k的部分中,靠近左端点的第一个大于r的值(这个求出来的只是原序列中顺序)在原序列中对应的值,1操作就是对应值变成inf(即一定大于k),特判k>n,输出k+1,若未找到,则输出n+1。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mid (l+r)/2
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll inf=1e10;
ll dat[4*maxn],num[maxn],b[maxn],id[4*maxn];
void build(int a,int l,int r){
if(l==r) dat[a]=num[l];
else{
build(a<<1,l,mid);
build(a<<1|1,mid+1,r);
dat[a]=max(dat[a<<1],dat[a<<1|1]);
}
}
void update(int a,int l,int r,int p){
if(l==r){
dat[a]=inf;
return;
}
if(p<=mid) update(a<<1,l,mid,p);
else update(a<<1|1,mid+1,r,p);
dat[a]=max(dat[a<<1],dat[a<<1|1]);
}
int query(int a,int l,int r,int s,int t,int k){
if(l==r){
if(dat[a]>k) return b[id[a]];
else return -1;
}
int k1=-1,k2=-1;
if(s<=mid && dat[a<<1]>k) k1=query(a<<1,l,mid,s,t,k);
if(k1!=-1) return k1;
if(t>mid && dat[a<<1|1]>k) k2=query(a<<1|1,mid+1,r,s,t,k);
return k2;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(dat,0,sizeof(dat));
int n,m,ans=0;
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%lld",&b[i]),num[b[i]]=i;
build(1,1,n);
memcpy(id,dat,sizeof(dat));
rep(i,1,m){
int t,l,r;
scanf("%d%d",&t,&l);
l^=ans;
if(t==1){
//cout<<l<<endl;
update(1,1,n,b[l]);
}
else{
scanf("%d",&r);
r^=ans;
if(r>n){
printf("%d",r+1);
continue;
}
ans=query(1,1,n,r,n,l);
if(ans==-1) ans=n+1;
printf("%d\n",ans);
}
}
}
}