Sequence II
题意:给你n个数,q次查询,每 次查询一个区间,求这个区间的不同数的最中间的那个的第一次出现的位置。主席树裸题吧。查询区间不同数的个数模板然后嵌套个二分,二分答案mid,判断[l,mid]之间不同数的个数是否大于等于(k+1)/2,是则更新右端点,反之更新左端点,注意强制在线的左端点不能变,另外用一个变量表示左端点,每次更新它即可。
const int N=2e5+10;
inline int sc()
{
char ch=getchar();
int sum=0;
while(!(ch>='0'&&ch<='9'))ch=getchar();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();
return sum;
}
int n,q,tot;
int a[N],T[N],lc[N*50],rc[N*50],c[N*50];
int ans[N];
int build(int l,int r)
{
int root=tot++;
c[root]=0;
if(l!=r)
{
int mid=(l+r)>>1;
lc[root]=build(l,mid);
rc[root]=build(mid+1,r);
}
return root;
}
int update(int root,int pos,int val)
{
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(pos<=mid)
{
lc[newroot]=tot++;
rc[newroot]=rc[root];
newroot=lc[newroot];
root=lc[root];
r=mid;
}
else
{
rc[newroot]=tot++;
lc[newroot]=lc[root];
newroot=rc[newroot];
root=rc[root];
l=mid+1;
}
c[newroot]=c[root]+val;
}
return tmp;
}
int query(int root,int pos)
{
int ret=0;
int l=1,r=n;
while(pos<r)
{
int mid=(l+r)>>1;
if(pos<=mid)
{
r=mid;
root=lc[root];
}
else
{
ret+=c[lc[root]];
root=rc[root];
l=mid+1;
}
}
return ret+c[root];
}
map<int,int>mp;
int main()
{
int t;
scanf("%d",&t);
int t1=t;
while(t--)
{
tot=0;
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++) a[i]=sc();
T[n+1]=build(1,n);
mp.clear();
for(int i=n; i>=1; i--)
{
if(mp.find(a[i])==mp.end()) T[i]=update(T[i+1],i,1);
else
{
int tmp=update(T[i+1],mp[a[i]],-1);
T[i]=update(tmp,i,1);
}
mp[a[i]]=i;
}
int l,r;
ans[0]=0;
for(int i=1; i<=q; i++)
{
l=sc();
r=sc();
int l1,r1;
l1=min((l+ans[i-1])%n+1,(r+ans[i-1])%n+1);
r1=max((l+ans[i-1])%n+1,(r+ans[i-1])%n+1);
l=l1,r=r1;
int k=(1+query(T[l1],r1))/2;
while(l1<=r1)
{
int mid=(l1+r1)>>1;
if(query(T[l],mid)>=k) ans[i]=mid,r1=mid-1;
else l1=mid+1;
}
}
printf("Case #%d: ",t1-t);
for(int i=1; i<=q; i++) printf("%d%c",ans[i],i==q?'\n':' ');
}
return 0;
}