题意:
思路:
乍一看以为是神题,想了半天都没想到怎么写,一看题解发现读错了。。。
和D-query这题一样,只不过因为要求最前面的数,所以需要从后向前添加。首先维护的不是权值线段树,1-n维护a[1]-a[n]出现过几次,如果之前某个数出现过,那么我们直接在前一棵树的基础上减去之前的位置,然后再添加进来
因为出现重复的时候后面每次要新建
2logn
2
l
o
g
n
个节点,所以空间开40倍
错误及反思:
其实基本就是主席树入门题改了改,早知道多读几次题了。。。。
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define lson l,m
#define rson m+1,r
const int N = 200100;
int sum[40*N],ls[N*40],rs[N*40],root[N],cnt,n,que,T,a[N],did[N];
void init(){
cnt=0;
memset(did,0,sizeof(did));
}
int build(int l,int r){
int rt=++cnt;
ls[rt]=rt; rs[rt]=rt; sum[rt]=0;
if(l==r) return rt;
int m=l+r>>1;
ls[rt]=build(lson); rs[rt]=build(rson);
return rt;
}
int update(int pre,int pos,int v,int l,int r){
int rt=++cnt;
ls[rt]=ls[pre]; rs[rt]=rs[pre]; sum[rt]=sum[pre]+v;
if(l==r) return rt;
int m=l+r>>1;
if(m>=pos) ls[rt]=update(ls[pre],pos,v,lson);
else rs[rt]=update(rs[pre],pos,v,rson);
return rt;
}
int querysum(int rt,int R,int l,int r){
if(r<=R) return sum[rt];
int m=l+r>>1;
if(m>=R) return querysum(ls[rt],R,lson);
return sum[ls[rt]]+querysum(rs[rt],R,rson);
}
int query(int rt,int k,int l,int r){
if(l==r) return l;
int m=(l+r)/2;
if(sum[ls[rt]]>=k) return query(ls[rt],k,lson);
return query(rs[rt],k-sum[ls[rt]],rson);
}
int main(){
scanf("%d",&T);
for(int I=1;I<=T;I++){
init();
scanf("%d%d",&n,&que);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
root[0]=build(1,n); root[n+1]=root[0];
for(int i=n;i>=1;i--){
if(did[a[i]]){
int temp=update(root[i+1],did[a[i]],-1,1,n);
root[i]=update(temp,i,1,1,n);
}
else{
root[i]=update(root[i+1],i,1,1,n);
}
did[a[i]]=i;
}
printf("Case #%d:",I);
int bef=0;
for(int i=1;i<=que;i++){
int l,r; scanf("%d%d",&l,&r);
int tl=l,tr=r;
l=min((tl+bef)%n+1,(tr+bef)%n+1);
r=max((tl+bef)%n+1,(tr+bef)%n+1);
int tot=querysum(root[l],r,1,n);
tot=(tot+1)/2;
bef=query(root[l],tot,1,n);
printf(" %d",bef);
}
puts("");
}
}