有分块过掉的大佬,我不会分块。。。
这道题的意思就是求区间内不同数字的个数k,然后求区间内有效下标中第k大的下标是谁(有效下标定义为该区间第一次出现某数字的位置)
强制在线。
那么我们可以用主席树维护区间内不同数字的个数,然后求区间第k大。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
struct Tree{
int lc,rc;
int sum;
}tree[9000000];
void pushup(int k){
tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
}
int root[maxn],tot;
int build(int l,int r){
int k=++tot;
tree[k].sum=0;
if(l==r) return k;
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
return k;
}
int updata(int p,int id,int val,int l,int r){
int k=++tot;
tree[k]=tree[p];
if(l==r){
tree[k].sum+=val;
return k;
}
int mid=(l+r)>>1;
if(id<=mid) tree[k].lc=updata(tree[p].lc,id,val,l,mid);
else tree[k].rc=updata(tree[p].rc,id,val,mid+1,r);
pushup(k);
return k;
}
//我现在是从后往前加的数;
int myfind(int p,int id,int l,int r){
if(l==r) return tree[p].sum;
int mid=(l+r)>>1;
if(id>mid) return tree[tree[p].lc].sum+myfind(tree[p].rc,id,mid+1,r);
return myfind(tree[p].lc,id,l,mid);
}
int myfind_k(int p,int id,int l,int r){
if(l==r) return l;
int mid=(l+r)>>1;
if(id<=tree[tree[p].lc].sum) return myfind_k(tree[p].lc,id,l,mid);
else return myfind_k(tree[p].rc,id-tree[tree[p].lc].sum,mid+1,r);
}
map<int,int> m;
void init(){
tot=0;
m.clear();
}
int a[maxn];
int res[maxn];
int main(){
//cout<<(int)(maxn+2*maxn*log2(maxn))<<endl;
//cout<<maxn*50<<endl;
int n,q;
int tt;
int c=0;
scanf("%d",&tt);
while(tt--){
init();
int ans=0;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
root[n+1]=build(1,n);
for(int i=n;i>=1;--i){
if(m.count(a[i])){
int t=updata(root[i+1],m[a[i]],-1,1,n);
root[i]=updata(t,i,1,1,n);
}
else{
root[i]=updata(root[i+1],i,1,1,n);
}
m[a[i]]=i;
}
int l,r,ll,rr;
for(int i=1;i<=q;++i){
scanf("%d%d",&ll,&rr);
l=min((ll+ans)%n+1,(rr+ans)%n+1);
r=max((ll+ans)%n+1,(rr+ans)%n+1);
ans=myfind(root[l],r,1,n);
ans=myfind_k(root[l],(ans+1)/2,1,n);
res[i]=ans;
}
printf("Case #%d:",++c);
for(int i=1;i<=q;++i) printf(" %d",res[i]);
printf("\n");
}
return 0;
}