首页 > 其他分享 >2.4章节检测

2.4章节检测

时间:2023-02-04 15:45:33浏览次数:53  
标签:章节 ch 加入 int 检测 sum pos mx 2.4

P4587 [FJOI2016]神秘数

一道主席树的模板题

我们先考虑暴力的做法,对于区间[l,r],我们先把里面的a[i]进行升序排序。设当前可以表示的数为[1,mx],对于要插入的数a[i],有两种可能:

  1. \(a_i<=mx+1,可以表示的数的范围变为[1,mx+a_i]\)
  2. \(a_i>mx+1,无法表示mx+1,停止加入\)

然后对暴力做法进行优化。
设已经加入了的数字的范围为[1,mx],可以表示的数字的范围为[1,pos];
首先可以知道,新加入的数的值肯定在[1,pos+1]里面,而小于mx的数已经被加入了,所以我们要加入值在[mx+1,pos+1]范围内的数。把值在[mx+1,pos+1]中的数的和记为sum,如果sum=0,则无法加入,输出pos+1;如果sum!=0,mx=pos+1,pos+=sum;

点击查看代码
#include<bits/stdc++.h>
using namespace std;

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=1e5+5;
int n,m,tot,a[N],maxn,rt[N];
struct ww{
	int val,ls,rs;
}tr[N<<5];

void insert(int &p,int pre,int l,int r,int x){
	p=++tot;
	tr[p]=tr[pre];tr[p].val+=x;
	if(l>=r)return ;
	int mid=(l+r)>>1;
	if(x<=mid){
		insert(tr[p].ls,tr[pre].ls,l,mid,x);
	}
	else{
		insert(tr[p].rs,tr[pre].rs,mid+1,r,x);
	}
}

int query(int p,int q,int l,int r,int x,int y){
	if(tr[p].val==tr[q].val)return 0;
	if(x<=l&&r<=y)return tr[q].val-tr[p].val;
	int mid=(l+r)>>1,res=0;
	if(x<=mid)res+=query(tr[p].ls,tr[q].ls,l,mid,x,y);
	if(y>mid)res+=query(tr[p].rs,tr[q].rs,mid+1,r,x,y);
	return res;
}

int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		maxn=max(maxn,a[i]);
	}
	for(int i=1;i<=n;i++){
		insert(rt[i],rt[i-1],1,maxn,a[i]);
	}
	m=read();int x,y;
	for(int i=1;i<=m;i++){
		x=read(),y=read();
		int mx=0,pos=0;
		while(1){
			int sum=query(rt[x-1],rt[y],1,maxn,mx+1,pos+1);
			if(!sum)break;
			mx=pos+1;pos+=sum;
		}
		printf("%d\n",pos+1);
	}
	return 0;
} 

标签:章节,ch,加入,int,检测,sum,pos,mx,2.4
From: https://www.cnblogs.com/mkik/p/17091627.html

相关文章