题解:我们可以倒序插入,然后我们查询的时候查询区间有多少个不同的数,接着查询之后假设有k个不同的数,接着我们可以根据区间有多少不同的数然后查询第(k+1)/2个数的第一个位置,加入我主席树左子树大于等于(k+1)/2个不同的数那么第一个位置肯定在左子树,否则在右子树,我们到最后L==R那么肯定是位置在L了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int mx = 2e5+5;
#define mid (L+R)/2
struct node{
int ls,rs;
int sum;
}T[50*mx];
int sz;
int root[mx];
void built(int &rt,int L,int R){
rt = sz++;
T[sz].sum = 0;
if(L==R)
return;
built(T[sz].ls,L,mid);
built(T[sz].rs,mid+1,R);
}
void creat(int &rt,int x,int L,int R,int p,int v){
rt = sz++;
T[rt] = T[x];
T[rt].sum+=v;
if(L==R)
return;
if(p<=mid) creat(T[rt].ls,T[x].ls,L,mid,p,v);
else creat(T[rt].rs,T[x].rs,mid+1,R,p,v);
}
int query(int end,int rt,int L,int R){
if(R<=end)
return T[rt].sum;
if(mid<end) return T[T[rt].ls].sum+query(end,T[rt].rs,mid+1,R);
else return query(end,T[rt].ls,L,mid);
}
int Query(int end,int rt,int L,int R,int k){
if(L==R)
return L;
int s = T[T[rt].ls].sum;
if(s<k) return Query(end,T[rt].rs,mid+1,R,k-s);
else return Query(end,T[rt].ls,L,mid,k);
}
map<int,int>mp;
int ans[mx];
int a[mx];
int main(){
int t;
scanf("%d",&t);
int ca = 1;
int n,m;
while(t--){
scanf("%d%d",&n,&m);
sz = 0;
int tmp;
built(root[n+1],1,n);
mp.clear();
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
for(int i = n; i >= 1; i--)
if(!mp[a[i]]){
creat(root[i],root[i+1],1,n,i,1);
mp[a[i]] = i;
}
else{
creat(tmp,root[i+1],1,n,mp[a[i]],-1);
creat(root[i],tmp,1,n,i,1);
mp[a[i]] = i;
}
printf("Case #%d: ",ca++);
for(int j = 1; j <= m; j++){
int l,r;
scanf("%d%d",&l,&r);
l = (l+ans[j-1])%n+1;
r = (r+ans[j-1])%n+1;
// cout<<l<<r<<endl;
if(l>r)
swap(l,r);
int k = query(r,root[l],1,n);
// cout<<k<<endl;
k = Query(r,root[l],1,n,(k+1)/2);
ans[j] = k;
printf("%d%c",k,j==m?'\n':' ');
}
}
return 0;
}