HDU 6703 array(主席树)
http://acm.hdu.edu.cn/showproblem.php?pid=6703
题意
给定一个长度为n的排列(1-n),要你实现操作两种,
1 x:给第x个数加上1e7;
2 x y:查询最小的且不小于y的且不在区间[1,x]里出现过的数。
题解
对权值建主席树,维护区间最小值,插入一个数相当于这个数被ban,进行1操作相当于取消ban,如果真去实现修改会比较麻烦,由于这个序列是一个排列,我们对一些数取消ban相当于答案可以直接出现在这些数里,所以我们可以用set保存一下取消ban的数然后联合查询即可。
1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #define IO std::ios::sync_with_stdio(0) 3 #include <bits/stdc++.h> 4 #define iter ::iterator 5 #define pa pair<int,ll> 6 using namespace std; 7 #define ll long long 8 #define mk make_pair 9 #define pb push_back 10 #define se second 11 #define fi first 12 ll mod=998244353; 13 const int N=1e5+50; 14 int a[N],rt[N],minv[N*20],ls[N*20],rs[N*20]; 15 int cnt,tot; 16 void build(int &o,int l,int r){ 17 o=++tot; 18 if(l==r){ 19 minv[o]=l; 20 return; 21 } 22 int m=(l+r)/2; 23 build(ls[o],l,m); 24 build(rs[o],m+1,r); 25 minv[o]=min(minv[ls[o]],minv[rs[o]]); 26 } 27 void up(int &o,int pre,int l,int r,int p){ 28 o=++cnt; 29 ls[o]=ls[pre]; 30 rs[o]=rs[pre]; 31 if(l==r){ 32 minv[o]=1e9; 33 return; 34 } 35 int m=(l+r)/2; 36 if(p<=m)up(ls[o],ls[pre],l,m,p); 37 else up(rs[o],rs[pre],m+1,r,p); 38 minv[o]=min(minv[ls[o]],minv[rs[o]]); 39 } 40 int qu(int o,int l,int r,int ql,int qr){ 41 if(l>=ql&&r<=qr){ 42 return minv[o]; 43 } 44 int m=(l+r)/2; 45 int res=1e9; 46 if(ql<=m)res=min(res,qu(ls[o],l,m,ql,qr)); 47 if(qr>m)res=min(res,qu(rs[o],m+1,r,ql,qr)); 48 return res; 49 } 50 int T,q,n; 51 int main(){ 52 scanf("%d",&T); 53 int h=1e5+1; 54 build(rt[0],1,h); 55 while(T--){ 56 scanf("%d%d",&n,&q); 57 cnt=tot; 58 for(int i=1;i<=n;i++){ 59 scanf("%d",&a[i]); 60 up(rt[i],rt[i-1],1,h,a[i]); 61 } 62 int t,x,y,ans=0; 63 set<int>s; 64 while(q--){ 65 scanf("%d%d",&t,&x); 66 x^=ans; 67 if(t==1)s.insert(a[x]); 68 else{ 69 scanf("%d",&y); 70 y^=ans; 71 int res1=qu(rt[x],1,h,y,h); 72 int res2=1e9; 73 auto it=s.lower_bound(y); 74 if(it!=s.end())res2=*it; 75 ans=min(res1,res2); 76 printf("%d\n",ans); 77 } 78 } 79 } 80 }