题意:给你一个区间 问你有总共多少个元素 ? 但是有一个条件 就是如果这个元素超过k个 当k个来算
思路:由于题目限制,所以只能是在线算法。如果知道一个区间,往左端加入一个点,只要知道这个的往右数第k个和它相同的数是否在这个区间么就可以了,右端同理。然后计算了一下复杂度和条件,发现可以使用莫队算法。
ps:其实可以使用在线的主席树,当时没想到,而且由于只记得莫队算法的思想,所以写了一个奇怪(偷懒版)的莫队算法,姿势其实并不标准,网络上有很多讲解的。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define MAX 100010
vector<int> f[MAX];
vector<int> b[MAX];
int l[MAX];
int r[MAX];
int s[400][400];
int a[MAX];
int v[MAX];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[a[i]].push_back(i);
if(f[a[i]].size()>k)
{
l[i]=f[a[i]][f[a[i]].size()-k-1];
}
}
for(int i=n;i>=1;i--)
{
b[a[i]].push_back(i);
if(b[a[i]].size()>k)
{
r[i]=b[a[i]][b[a[i]].size()-k-1];
}
else
r[i]=n+1;
}
for(int i=0;i*300<n;i++)
{
int sum=0;
memset(v,0,sizeof(v));
for(int j=i*300+1;j<=n;j++)
{
v[a[j]]++;
if(v[a[j]]<=k)
sum++;
if(j%300==0)
s[i][j/300]=sum;
}
}
int m,x,y;
int ans=0;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
x=(ans+x)%n+1;
y=(ans+y)%n+1;
if(x>y)
swap(x,y);
if(y-x<600)
{
ans=0;
memset(v,0,sizeof(v));
for(int j=x;j<=y;j++)
{
v[a[j]]++;
if(v[a[j]]<=k)
ans++;
}
}
else{
int nowl=(x/300+1)-(x%300==1);
int nowr=y/300;
ans=s[nowl][nowr];
int L=nowl*300+1;
int R=nowr*300;
while(L>x){
L--;
if(r[L]>R)
ans++;
}
while(R<y){
R++;
if(l[R]<x)
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}