题目链接:https://codeforces.com/contest/813/problem/E
题目大意:
给出一个序列,长度为N,进行Q次询问,强制在线
每次询问[l,r]内(cnt表示i出现的次数):
∑ m i n ( c n t i , k ) \sum{min(cnt_i,k)} ∑min(cnti,k)
题目思路
这题与区间内不同数字的种数类似
可以用主席树、或者树状数组进行实现
考虑那题的实现方法:记录某个数上一次出现的位置
所以同样的,这题与那题类似,只需要:记录某个数前面第k次出现的位置
这样就保证了出现次数不可能超过k
这里用主席树维护就好了
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 3e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>b[maxn];
int pos[maxn];
struct node{
int l,r;
int w;
}t[maxn*30];
int root[maxn*30];
int cnt = 0;
void Insert(int &now,int pre,int l,int r,int pos,int w){
t[now = ++cnt] = t[pre];
t[now].w += w;
if(l == r) return ;
int mid = (l+r)/2;
if(pos <= mid) Insert(t[now].l,t[pre].l,l,mid,pos,w);
else Insert(t[now].r,t[pre].r,mid+1,r,pos,w);
}
ll Find(int now,int l,int r,int pos){
if(l == r) return t[now].w;
int mid = (l+r)/2;
if(pos <= mid) return Find(t[now].l,l,mid,pos) + t[t[now].r].w;
return Find(t[now].r,mid+1,r,pos);
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++){
int x;read(x);
Insert(root[i],root[i-1],1,n,i,1);
b[x].push_back(i);
if(b[x].size()>m){
Insert(root[i],root[i],1,n,b[x][pos[x]],-1);
pos[x]++;
}
}
read(p);
int last = 0;
for(int i=1;i<=p;i++){
int l,r;read(l);read(r);
l = (last+l)%n+1,r = (last+r)%n+1;
if(l>r) swap(l,r);
last = Find(root[r],1,n,l);
printf("%d\n",last);
}
return 0;
}
/***
10
0101011101
****/