hdu4417(离散化+树状数组)

Super Mario

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


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
 
 
本题要求一个区间内小于某个数的个数
由于询问次数之巨,不能简单模拟处理,可以联想线段树,线段树可以快速查询小于某个数的个数,由于[0, 1000000000]区间数目巨,必须进行离散化处理,观察题目可知1 <= n <=10^5, 1 <= m <= 10^5数目显现,可以以此为区间建立线段树,先将路线的点和查询的区间按高度排序,再在一个外层循环中处理每个查询区间,内层循环为路线上的点,读入一个点,若点的高度小于等于当前区间的高度,则将点插入线段树,若点的高度大于当前区间高度,由于事先将线路上的所有点都排过序,则此时小于该区间高度的所有点都已插入线段树中,我们只需在此时查询该需查询区间元素个数即可;然后处理下一个查询区间…直至结束.插入元素时只需在该插入位置加1,查询区间只需统计该区间1的个数,线段树的操作退化为频繁地加1和查询,此时可以用实现方便\代码少的树状数组代替线段树.
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int MAX=100000+10;
struct node1
{
	int ind,hei;
}point[MAX];
int Lowbit[MAX];
int C[MAX];
struct node2
{
	int left,right,hei,ind,num;
}query[MAX];

bool cmp1(node1 a,node1 b)
{
	return a.hei<b.hei;
}

bool cmp2(node2 a,node2 b)
{
	return a.hei<b.hei;
}

bool cmp3(node2 a,node2 b)
{
	return a.ind<b.ind;
}

int QuerySum(int p)
//查询原数组中下标1-p的元素的和 
{ 
   int nSum = 0; 
   while( p > 0 ) 
   {  
      nSum += C[p]; 
      p -= Lowbit[p]; 
   } 
    return nSum; 
} 

void Modify( int p,int val) 
//原数组中下表为p的元素+val,导致C[]数组中部分元素值的改变
{ 
    while( p <= MAX) 
   { 
      C[p] += val; 
      p += Lowbit[p]; 
    } 
} 

int main()
{
	int i,cas,n,m,cnt_q,tag=1;
	for(i=1;i<=MAX;i++)
		Lowbit[i]=i&(-i);
	cin>>cas;
	while(cas--)
	{
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)
		{
			scanf("%d",&point[i].hei);
			point[i].ind=i;
		}
		sort(point+1,point+n+1,cmp1);

		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&query[i].left,&query[i].right,&query[i].hei);
			query[i].left++,query[i].right++;
			query[i].ind=i;
		}
		sort(query+1,query+m+1,cmp2);

		memset(C,0,sizeof(C));
		cnt_q=1;
	
		int k=1;
		for(i=1;i<=m;i++)
		{
			while(k<=n&&point[k].hei<=query[i].hei)
			{
				Modify(point[k].ind,1);
				k++;
			}
			query[i].num=QuerySum(query[i].right)-QuerySum(query[i].left-1);
		}

 
		sort(query+1,query+m+1,cmp3);
		printf("Case %d:\n",tag++);
		for(i=1;i<=m;i++)
			printf("%d\n",query[i].num);

	}
	return 0;
}

你可能感兴趣的:(数据结构,排序,线段树)