[CF840D][主席树]Destiny

CF840D

p = r − l + 1 k + 1 p=\frac{r-l+1}{k}+1 p=krl+1+1,则如果一个权值出现了不小于p次,那我们将 [ l , r ] [l,r] [l,r]排序,这个权值一定在 p , 2 p . . . , k p p,2p...,kp p,2p...,kp中的任意一个地方出现过
也就是说,我们找到这些位置上的数,再判断它们的出现次数是否小于p即可,用主席树可以方便实现

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=3e5+5;
int a[N],rt[N],cnt=0;
namespace President_tree{
	struct seg{int sum,ls,rs;}tr[N*80];
	#define lc(k) tr[k].ls
	#define rc(k) tr[k].rs
	void build(int &k,int l,int r){
		k=++cnt;tr[k].sum=0;
		if(l==r) return;
		int mid=l+r>>1;
		build(lc(k),l,mid);build(rc(k),mid+1,r);
	}
	void ins(int &k1,int k2,int l,int r,int v){
		k1=++cnt;tr[k1]=tr[k2];++tr[k1].sum;
		if(l==r) return;
		int mid=l+r>>1;
		if(v<=mid) ins(lc(k1),lc(k2),l,mid,v);
		else ins(rc(k1),rc(k2),mid+1,r,v);
	}
}
using namespace President_tree;
int main(){
	int n=read(),q=read();
	for(int i=1;i<=n;i++) a[i]=read();
	build(rt[0],1,n);
	for(int i=1;i<=n;i++) rt[i]=rt[i-1],ins(rt[i],rt[i],1,n,a[i]);
	while(q--){
		int l=read(),r=read(),k=read(),ans=-1;
		int nw=(r-l+1)/k;
		int L=1,R=n,k1=rt[r],k2=rt[l-1];
		if(!nw){
			while(L<R){
				int mid=L+R>>1;
				if(tr[lc(k1)].sum-tr[lc(k2)].sum>0) k1=lc(k1),k2=lc(k2),R=mid;
				else k1=rc(k1),k2=rc(k2),L=mid+1;
			}
			cout<<L<<"\n";
		}
		else{
			for(int i=nw;i<=r-l+1;i+=nw){
				L=1,R=n,k1=rt[r],k2=rt[l-1];int now=i;
				while(L<R){
					int mid=L+R>>1,del=tr[lc(k1)].sum-tr[lc(k2)].sum;
					if(del>=now) k1=lc(k1),k2=lc(k2),R=mid;
					else k1=rc(k1),k2=rc(k2),L=mid+1,now-=del;
				}
				if((tr[k1].sum-tr[k2].sum)*k>r-l+1 && (L<ans || ans==-1)) ans=L;
			}
			cout<<ans<<"\n";
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值