件名リンク:https://codeforces.com/contest/813/problem/E
本旨:
長さがNのシーケンスが与えられると、Q回の照会が実行され、
各照会内で強制的にオンラインになります[l、r](cntはiの発生数を表します):
∑ min(cnti、k)\ sum {min(cnt_i、k)}∑m i n (c n t私、k )
トピックのアイデア
この質問は、間隔内の異なる数
の数に似ています。議長ツリーまたはツリーのような配列で実装できます。
その質問の実装方法を検討してください。记录某个数上一次出现的位置
同じように、この質問はその質問に似ていますが、必要性:记录某个数前面第k次出现的位置
これにより、発生数がkを超えないことが保証
されます。議長ツリーを使用して維持することをお勧めします。
コード:
/*** 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
****/