第一道主席树题目。
题意:给定N个数,以及Q个询问,每个询问给出[L,R] 现在问在这个区间选最多的数,使得每个数出现次数不能大于K,强制在线。
题解:预处理每一个数,找到从该数(不包括)开始第K个相同的数,保存这个位置,题目转变成[L,R]中(大于R) 大于等于R+1的数的个数有多少个,主席树操作。
没找到好的主席树模板,码风不好。
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
#define ll long long
#define INF 2147483647
#define CLR(a) memset(a, 0, sizeof(a))
using namespace std;
const int maxn=2e5+10;
int n,k,q;
int a[maxn],pos[maxn];
vector<int> loc[maxn];
struct node{
int l,r,cnt;
}tree[maxn*40];//WA最坏情况下开40倍
int tot,root[maxn];
int build(int l,int r){
int rt=++tot;
tree[rt].l=0;
tree[rt].r=0;
tree[rt].cnt=0;
if(l==r) return rt;
else{
int mid=(l+r)>>1;
tree[rt].l=build(l,mid);
tree[rt].r=build(mid+1,r);
return rt;
}
}
int update(int l,int r,int pre,int x){
int rt=++tot;
tree[rt]=tree[pre];
tree[rt].cnt++;
if(l==r) return rt;
int mid=(l+r)>>1;
if(mid>=x) tree[rt].l=update(l,mid,tree[pre].l,x);
else tree[rt].r=update(mid+1,r,tree[pre].r,x);
return rt;
}
int query(int l,int r,int st,int ed,int val){
if(l==r) return tree[ed].cnt-tree[st].cnt;
int mid=(l+r)>>1;
int ans=0;
if(val<=mid) ans+=query(l,mid,tree[st].l,tree[ed].l,val)+tree[tree[ed].r].cnt-tree[tree[st].r].cnt;
else ans+=query(mid+1,r,tree[st].r,tree[ed].r,val);
return ans;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
loc[a[i]].push_back(i);
pos[i]=n+1;
}
for(int i=1;i<=100000;i++){
int sz=loc[i].size();
if(sz>k){
for(int j=0;j+k<sz;j++)
pos[loc[i][j]]=loc[i][j+k];
}
}
root[0]=build(1,100001);
for(int i=1;i<=n;i++)
root[i]=update(1,100001,root[i-1],pos[i]);
scanf("%d",&q);
int lans=0;
for(int i=1;i<=q;i++){
int x,y;
scanf("%d%d",&x,&y);
int l=(x+lans)%n+1;
int r=(y+lans)%n+1;
if(l>r) swap(l,r);
lans=query(1,100001,root[l-1],root[r],r+1);//WA
printf("%d\n",lans);
}
return 0;
}