您的位置:首页 > 其它

HDU 4417 Super Mario(划分树+二分)

2016-04-21 17:11 483 查看


Super Mario

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4349 Accepted Submission(s): 2016



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

2012 ACM/ICPC Asia Regional Hangzhou Online

题意:
给你n个数和m询问,找出指定区间内的小于等于某个数的个数。
思路:
看范围是10^5很显然比较适合划分树去做。
划分树解决的题目是第几大的数。
所以和上个题目差不多。
二分查找级别。找到后输出K即可!
查找上限!
#include<stdio.h>
#include<algorithm>
using namespace std;
const int M = 100000 + 5;
int tree[20][M],sorted[M];
int toLeft[20][M];
int n,m,nl,nr;
void build(int level,int left,int right){
if(left==right)return ;
int mid=(left+right)>>1;
int i;
int suppose;
suppose=mid-left+1;
for(i=left;i<=right;i++){
if(tree[level][i]<sorted[mid]){
suppose--;
}
}
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{
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);
}
int query(int level,int left,int right,int qleft,int qright,int k){
if( qleft==qright)
return tree[level][qleft];
int s;
int ss;
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 findup(int low,int high,int val){
int mid = (low+high+1)>>1;
while(low < high){
int ans = query(0,1,n,nl,nr,mid);
if (ans <= val)low = mid;
else high = mid-1;
mid = (low+high+1)>>1;
}
if (query(0,1,n,nl,nr,mid) <= val)return mid;
return 0;
}
int main(){
int T,cnt=0;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; ++i){
scanf("%d",&tree[0][i]);
sorted[i] = tree[0][i];
}
sort(sorted+1,sorted+1+n);
build(0,1,n);
printf("Case %d:\n",++cnt);
while(m--){
int k;
scanf("%d%d%d",&nl,&nr,&k);
nl++;nr++;
int ans = findup(1,nr-nl+1,k);
printf("%d\n",ans);
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: