题意:给你长度为n的序列,有q个询问,询问[l,r]区间内相同数字最多选k个的总个数。
题解:建立关于位置的主席树,利用差分的思想,对于新加入的一个数,当前位置+1,并在之前第i-k个位置-1,最后询问root[r]中区间[l,r]的总和。
AC代码:
#include<stdio.h>
#include<vector>
#include<algorithm>
#define N 100005
using namespace std;
vector<int>vt[N];
int tree[N*36],lchild[N*36],rchild[N*36],root[N],tot;
void insert(int last,int cur,int x,int L,int R,int k)
{
tree[cur]=tree[last]+k;
lchild[cur]=lchild[last];
rchild[cur]=rchild[last];
if(L==R)return ;
int mid=L+R>>1;
if(x<=mid)insert(lchild[last],lchild[cur]=++tot,x,L,mid,k);
else insert(rchild[last],rchild[cur]=++tot,x,mid+1,R,k);
}
int query(int l,int r,int L,int R,int root)
{
if(l<=L&&R<=r)return tree[root];
int mid=L+R>>1;
if(r<=mid)return query(l,r,L,mid,lchild[root]);
else if(l>mid)return query(l,r,mid+1,R,rchild[root]);
else return query(l,mid,L,mid,lchild[root])+query(mid+1,r,mid+1,R,rchild[root]);
}
int main()
{
int n,k,q,x;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
vt[x].push_back(i);
insert(root[i-1],root[i]=++tot,i,1,n,1);
if(vt[x].size()>k)
{
int now=++tot;
insert(root[i],now,vt[x][vt[x].size()-k-1],1,n,-1);
root[i]=now;
}
}
int last=0;
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
l=(l+last)%n+1;
r=(r+last)%n+1;
if(l>r)swap(l,r);
last=query(l,r,1,n,root[r]);
printf("%d\n",last);
}
}