http://acm.hdu.edu.cn/showproblem.php?pid=5919
题意:求给定一个区间,在对前边一个答案进行运算后得到一个新的区间,然后问这个区间里面有k个不同的数,把它们第一次出现的位置从小到大排序,问第k/2个位置是什么;
思路:从后往前插入,同时在插入前删除之前插入的那个,然后求一个区间的个数就是在左端点的那个树上求询问区间的数的个数;因为左子树就是去重了的区间,再到那个左线段树区间上求第K大。
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<algorithm> #include<map> #include<vector> #include<string> #include<set> #define ll long long using namespace std; int n,cnt; const int maxn=200010; int a[maxn],pre[maxn],root[maxn]; struct node { int l,r,sum; }T[maxn*40]; void update(int l,int r,int &x,int y,int pos,int val) { T[++cnt]=T[y]; T[cnt].sum+=val; x=cnt; if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos,val); else update(mid+1,r,T[x].r,T[y].r,pos,val); } int query(int o,int l,int r,int L,int R) { if(L<=l&&R>=r) return T[o].sum; int mid=(l+r)>>1; int ans=0; if(L<=mid) ans+=query(T[o].l,l,mid,L,R); if(R>mid) ans+=query(T[o].r,mid+1,r,L,R); return ans; } int getans(int o,int l,int r,int k) { if(l==r) return l; int ans=T[T[o].l].sum; int mid=(l+r)>>1; if(ans>=k) return getans(T[o].l,l,mid,k); else return getans(T[o].r,mid+1,r,k-ans); } int main() { int t; scanf("%d",&t); int o=0; while(t--) { o++; int m,ans=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } memset(pre,-1,sizeof(pre)); memset(root,0,sizeof(root)); cnt=0; T[n+1].l=T[n+1].r=T[n+1].sum=0; for(int i=n;i>=1;i--) { if(pre[a[i]]==-1) update(1,n,root[i],root[i+1],i,1); else { int temp; update(1,n,temp,root[i+1],pre[a[i]],-1); update(1,n,root[i],temp,i,1); } pre[a[i]]=i; } int u,v; printf("Case #%d:",o); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); u=(u+ans)%n+1; v=(v+ans)%n+1; if(u>v) swap(u,v); int k=(query(root[u],1,n,u,v)+1)>>1; ans=getans(root[u],1,n,k); printf(" %d",ans); } printf("\n"); } }