您的位置:首页 > 其它

HDU 4417 (二分 + 区间第k大)

2016-07-19 14:22 369 查看

题目:

查询区间【L,R】中有多少数 比给定的 H 小。

分析:

我们可以这么想, H 一定会比 区间的第 X 大 ,第 X +1 小。

怎么确定 X。

这是一个单调的问题, 所以二分 + 区间第 K 大就可以确定了。

Code:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100000 + 131;
int sorted[maxn];
int tree[30][maxn];
int toleft[30][maxn];

void Build(int l, int r, int dep) {
if(l == r) return ;
int mid = (l + r) >> 1;
int same = mid - l + 1;
for(int i = l; i <= r; ++i) if(tree[dep][i] < sorted[mid]) same--;
int lpos = l, rpos = mid + 1;
for(int i = l; i <= r; ++i) {
if(tree[dep][i] < sorted[mid])
tree[dep+1][lpos++] = tree[dep][i];
else if(tree[dep][i] == sorted[mid] && same > 0)
tree[dep+1][lpos++] = tree[dep][i], same--;
else tree[dep+1][rpos++] = tree[dep][i];
toleft[dep][i] = toleft[dep][l-1] + lpos - l;
}
Build(l,mid,dep+1), Build(mid+1, r, dep+1);
}

int Query(int L, int R, int l, int r, int dep, int k) {
if(l == r) return tree[dep][l];
int mid = (L + R) >> 1;
int cnt = toleft[dep][r] - toleft[dep][l-1];
if(cnt >= k) {
int newl = L + toleft[dep][l-1]-toleft[dep][L-1];
int newr = newl + cnt -1;
return Query(L,mid,newl, newr,dep+1, k);
}
else {
int newr = r + toleft[dep][R] - toleft[dep][r];
int newl = newr -(r-l-cnt);
return Query(mid+1,R, newl, newr,dep+1, k-cnt);
}
}

int main() {
int n, m, T;
ios::sync_with_stdio(false);
cin >> T;
for(int kase = 1; kase <= T; ++kase) {
memset(tree,0,sizeof(tree));
cin >> n >> m;
for(int i = 1; i <= n; ++i)
cin >> tree[0][i], sorted[i] = tree[0][i];
sort(sorted+1, sorted+1+n);
Build(1,n,0);
printf("Case %d:\n",kase);
while(m--) {
int s, t, h;
cin >> s >> t >> h;
s++, t++;
int ans = 0;
int l = 1, r = (t-s) + 1;
while(l <= r) {
int mid = (l + r) >> 1;
int temp = Query(1,n,s,t,0,mid);
if(temp <= h) {
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分 区间第K-大