hdu 4417 划分树加二分 求区间内小于num的数的个数

本文深入探讨了游戏开发领域的核心技术,包括游戏引擎、动画、3D空间视频等,旨在为开发者提供全面的游戏开发知识和实践经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Super Mario

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 771    Accepted Submission(s): 423


Problem Description
Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.
 

Input
The first line follows an integer T, the number of test data.
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)
 

Output
For each case, output "Case X: " (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query.
 

Sample Input
  
1 10 10 0 5 2 7 5 4 3 8 7 7 2 8 6 3 5 0 1 3 1 1 9 4 0 1 0 3 5 5 5 5 1 4 6 3 1 5 7 5 7 3
 

Sample Output
  
Case 1: 4 0 0 3 1 2 0 1 5 1
 

Source
 

题意:

输入cas 

n  m

输入n个数

输入m组 每组表示一个范围内l r 中小于num的数的个数

注意从l是0开始的


思路 :区间内找数  很容易联想到划分树  划分树是用来求一个区间内的第k大的数

那么我们可以找出第1第2第3.。。。。。。大数的值 和num进行比较

用二分法很容易找到第几大的数小于且等于num

下面的几乎就是个模板       二分法居然也搞了我一下 坑爹


#include<stdio.h> 
#include<algorithm> 
using namespace std; 
#define M 100005 
int tree[40][M],sorted[M]; 
int toLeft[40][M]; 
void build(int level,int left,int right){ 	
	if(left==right)return ; 	
	int mid=(left+right)>>1; 	
	int i; 	
	int suppose;//假设在中位数sorted[mid]左边的数都全部小于sorted[mid] 	
	suppose=mid-left+1; 	
	for(i=left;i<=right;i++){ 		
		if(tree[level][i]<sorted[mid]){ 			
			suppose--; 			
		} 		
	} 	
	//如果suppose==1,则说明数组中值为sorted[mid]只有一个数。比如序列:1 3 4 5 6,sorted[mid]=4 	
	/*如果suppose>1,则说明数组中左半边值为sorted[mid]的不止一个数,为mid-suppose。比如序列:1 4 4 4 6,sorted[mid]=4 	
	*/ 	
	int lpos=left,rpos=mid+1; 	
	for(i=left;i<=right;i++){ 		
		if(i==left)
		{//这里是预处理,相当与初始化 			
			toLeft[level][i]=0; 
		}
		else
		{ 	
			toLeft[level][i]=toLeft[level][i-1]; 	
		} 
		if(tree[level][i]<sorted[mid]){//划分到中位数左边 		
			toLeft[level][i]++; 		
			tree[level+1][lpos++]=tree[level][i]; 		
		}else if(tree[level][i]>sorted[mid]){//划分到中位数右边 		
			tree[level+1][rpos++]=tree[level][i]; 		
		}else{//这里,suppose大于0的数划分到中位数的左边 		
			if(suppose!=0){//这里的处理太巧妙了!帅气! 		
				suppose--; 
				toLeft[level][i]++; 		
				tree[level+1][lpos++]=tree[level][i]; 		
			}else{//表示 		
				tree[level+1][rpos++]=tree[level][i]; 		
			} 		
		} 	
	} 	
	build(level+1,left,mid); 	
	build(level+1,mid+1,right); 	
} 
//在[left,right]数据中查询[qleft,qright]中第k大的数据 
int query(int level,int left,int right,int qleft,int qright,int k){ 	
	if( qleft==qright) 		
		return tree[level][qleft]; 	
	int s;//代表[left,qleft)之间有多个个元素被分到左边 	
	int ss;//[qleft, qright]内将被划分到左子树的元素数目 	
	int mid=(left+right)>>1; 	
	if(left==qleft){ 		
		s=0; 		
		ss=toLeft[level][qright];		
	}else{ 	
		s=toLeft[level][qleft-1]; 	
		ss=toLeft[level][qright]-s; 	
	} 
	int newl,newr; 
	if(k<=ss){//查询左边 		
		newl=left+s; 	
		newr=left+s+ss-1; 	
		return query(level+1,left,mid,newl,newr,k); 	
	}else{//查询右边 		
		newl=mid-left+1+qleft-s; 		
		newr=mid-left+1+qright-s-ss; 	
		return query(level+1,mid+1,right,newl, newr,k - ss); 		
	} 	
} 
int main()
{ 	
	int n,m,cas,ca=0;
	scanf("%d",&cas);
	while(cas--)
	{
		printf("Case %d:\n",++ca);
	   scanf("%d %d",&n,&m);	
        int i; 		
        for(i=1;i<=n;i++){ 			
            scanf("%d",&tree[0][i]); 			
			sorted[i]=tree[0][i]; 			
        } 		
        sort(sorted+1,sorted+n+1); 		
        build(0,1,n); 	
        int ql,qr,num,ans=0; 
		for(i=0;i<m;i++)
		{ 			
            scanf("%d %d %d",&ql,&qr,&num);
			ql++;qr++;//注意这里哦  题意是按从0开始的 
			int mid,left=1,right=qr-ql+1,ans=0;
			mid=(left+right)/2;
			while(left<=right)//别少了等于号
			{
				mid=(left+right)/2;
                if(query(0,1,n,ql,qr,mid)>num) right=mid-1;
				else  {ans=mid;left=mid+1;}//我一开始写的二分法居然不知道是哪里出错了一个劲RE
			}
			printf("%d\n",ans);
		} 		
	} 		return 0; 	
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值