#主席树#CF813E Army Creation

题目

\(n\) 个数 \(a_i\) , \(k\) 为给定值, \(q\) 次询问。

每次问 \([l,r]\) 内最多可以选多少个数,

满足同一个数的出现次数不超过 \(k\)

不带修,强制在线


分析

考虑对于每一种数开一个vector,然后在主席树中存入\(now-k\)的位置,
那么对于每次询问就是\([0,l)\)范围内有多少个数,直接在主席树里查询即可


代码

#include <cstdio>
#include <cctype>
#include <vector>
#define rr register
using namespace std;
const int N=100101; vector<int>K[N];
inline signed iut(){
    rr int ans=0,f=1; rr char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans*f;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
struct Chair{
    int w[N<<5],ls[N<<5],rs[N<<5],cnt;
    inline void build(int &rt,int l,int r){
        w[rt=++cnt]=0; rr int mid=(l+r)>>1;
        if (l<r) build(ls[rt],l,mid),build(rs[rt],mid+1,r); 
    }
    inline void update(int &rt,int l,int r,int k){
        rr int trt=++cnt,mid=(l+r)>>1;
        ls[trt]=ls[rt],rs[trt]=rs[rt],w[trt]=w[rt]+1,rt=trt;
        if (l==r) return;
        k<=mid?update(ls[trt],l,mid,k):update(rs[trt],mid+1,r,k);
    }
    inline signed query(int L,int R,int l,int r,int k){
    	if (l==r) return w[R]-w[L];
    	rr int mid=(l+r)>>1;
    	if (k<=mid) return query(ls[L],ls[R],l,mid,k);
    	    else return query(rs[L],rs[R],mid+1,r,k)+w[ls[R]]-w[ls[L]];
    } 
}Tre;
int rt[N],n,m,k,a[N];
signed main(){
	n=iut(),k=iut(),Tre.build(rt[0],0,n);
	for (rr int i=1;i<=n;++i){
		rr int x=iut(),pos=0,len=K[x].size();
		if (len>=k) pos=K[x][len-k];
		Tre.update(rt[i]=rt[i-1],0,n,pos);
		K[x].push_back(i);
	}
	for (rr int Q=iut(),lans=0;Q;--Q){
		rr int l=(lans+iut())%n+1,r=(lans+iut())%n+1;
		if (l>r) l^=r,r^=l,l^=r;
		print(lans=Tre.query(rt[l-1],rt[r],0,n,l-1)),putchar(10);
	}
    return 0;
}
posted @ 2021-07-07 09:30  lemondinosaur  阅读(30)  评论(0编辑  收藏  举报