题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6703
题意:给你一个n的全排列A,然后给m个操作,第一类操作给一个数k,将A[k^lastans]增加1000000;第二类操作在区间给两个数v,k,要求一个最小的ans,不与区间A[1,v^lastans]中任意一个数相等,并且不小于k^lastans。
先看如果没有进行过第一种操作,对于每一次第二类操作,设r=v^lastans,k=k^lastans,因为A是一个n的全排列,如果ans不与A[1,r]中任意一个数相等,那么ans就是在A[r+1,n]中一个数,当然这个数要不小于k,所以为了防止出现在A[r+1,n]中一个数都小于k,我们在将A[n+1]赋为n+1,那么这时第二类操作的答案就是在A[r+1,n+1]中寻找一个不小于k的最小的数。这个过程可以用主席树解决。
那么进行过第一类操作并不是意味着要更改主席树(而且改了主席树全排列就失效了),回到原问题,因为第一类操作是将一个数增加1000000,远大于n,那么显然原来的这个数就在A中不存在了,那么我们将这个数也纳入考虑范围之内,随着1操作的进行,我们就要在多个这样的数中选择最小,并且不小于k的数就行了。
因为1操作将一个数增大,所以对于主席树的查询是没有影响的,主席树可以不用修改。
我们只需要取两个找到的答案的最小值,就是最终的答案。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <algorithm> #include <set> #define MAXN 100010 #define mid (l+r)/2 using namespace std; int T,n,q,a[MAXN],root[MAXN]; const int inf=0x3f3f3f3f; set<int> st; struct Tree{ int tot; int L[MAXN<<5],R[MAXN<<5],sum[MAXN<<5]; void init() { tot=0; memset(L,0,sizeof(L)); memset(R,0,sizeof(R)); memset(sum,0,sizeof(sum)); } int build(int l,int r) { int id=++tot; if(l<r) { L[id]=build(l,mid); R[id]=build(mid+1,r); } return id; } int update(int pre,int l,int r,int x) { int id=++tot; L[id]=L[pre];R[id]=R[pre];sum[id]=sum[pre]+1; if(l<r) { if(x<=mid) L[id]=update(L[pre],l,mid,x); else R[id]=update(R[pre],mid+1,r,x); } return id; } int ask(int u,int v,int l,int r,int k) { if(sum[v]==sum[u]) return inf; if(l==r) return l; int ans=inf; if(k<=mid) ans=ask(L[u],L[v],l,mid,k); if(ans==inf) ans=ask(R[u],R[v],mid+1,r,k); return ans; } }tree; int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); a[n+1]=n+1; st.clear(); tree.init(); root[0]=tree.build(1,n+1); for(int i=1;i<=n+1;i++) root[i]=tree.update(root[i-1],1,n+1,a[i]); int ans=0; for(int i=1,type,u,k;i<=q;i++) { scanf("%d",&type); if(type==1) { scanf("%d",&k); k^=ans; st.insert(a[k]); } else { scanf("%d%d",&u,&k); u^=ans;k^=ans; int ans1=tree.ask(root[u],root[n+1],1,n+1,k); int ans2=inf; set<int>::iterator it=st.lower_bound(k); if(it!=st.end()) ans2=*it; ans=min(ans1,ans2); printf("%d ",ans); } } } return 0; }
---恢复内容结束---