牛客竞赛数据结构专题班树状数组、线段树练习题

F.little w and Discretization

题意:找区间[l,r]内离散化后和原来的值不同大小的数的个数
思路:先求区间mex,同时记录区间有多少个数,再 用区间长度减去(区间内小于mex数的个数)

const int maxn=1e6+5;
int n,cnt,a[maxn],m,root[maxn],b[maxn],c[maxn];
struct node{
	int l,r,val,he;
}tr[maxn<<4];
int update(int pre,int l,int r,int val,int pos){
	int now=++cnt;
	tr[now]=tr[pre];
	tr[now].he++;// 记录当前节点包含了he个数 
	if(l==r){
		tr[now].val=pos;//记录权值l最后一次出现的位置pos 
		return now;
	}
	int mid=(l+r)>>1;
	if(val<=mid)tr[now].l=update(tr[pre].l,l,mid,val,pos);
	else tr[now].r=update(tr[pre].r,mid+1,r,val,pos);
	tr[now].val=min(tr[tr[now].l].val,tr[tr[now].r].val);//区间最小值 
	return now;
}
int query(int now,int l,int r,int d){//求小于d的最大值 
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(tr[tr[now].l].val<d)return query(tr[now].l,l,mid,d);
	return query(tr[now].r,mid+1,r,d);
}
int getsum(int pre,int now,int l,int r,int x,int y){//小于d的有多少个数 
	if(x<=l&&r<=y)return tr[now].he-tr[pre].he;
	int mid=(l+r)>>1,ans=0;
	if(x<=mid)ans+=getsum(tr[pre].l,tr[now].l,l,mid,x,y);
	if(y>mid)ans+=getsum(tr[pre].r,tr[now].r,mid+1,r,x,y);
	return ans;
}
int main(){
    while(~scanf("%d",&n)){
    	cnt=0;
    	for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]>n)root[i]=root[i-1];
            else root[i]=update(root[i-1],1,n,a[i],i);
        }
	    scanf("%d",&m);
	    while(m--){
		    int l,r;
		    scanf("%d%d",&l,&r);
		    int d=query(root[r],1,n,l);
		    int he=getsum(root[l-1],root[r],1,n,1,d);
		    printf("%d\n",r-l+1-he);//区间长度-小于mex的数的个数 
	    }
	}
}

你可能感兴趣的:(牛客练习题,数据结构,数据结构)