看了大牛的思路http://blog.csdn.net/fp_hzq/article/details/8010322#comments
每次询问区间内小于等于k的数有几个,很明显符合划分树的范畴,然后只要改改query函数,没次对于大于中间的数就加上划分到左边的个数,否则不管。注意了:就是可能区间会划分到空,还有可能只有一个元素,而且等于查找的数,要特殊处理下
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define M 100001
#define md(x, y) (((x)+(y))>>1)
int sorted[M]; // 对原来集合中的元素排序后的值。
struct node {
int val[M]; // val 记录第 k 层当前位置的元素的值
int num[M]; // num 记录元素所在区间的当前位置之前进入左孩子的个数
}t[20];
int n,m,k;
void build(int lft, int rht, int p) {
if(lft == rht) return;
int i, mid = md(lft, rht);
int isame = mid - lft + 1, same = 0;
for(i = lft; i <= rht; i++)
if(t[p].val[i] < sorted[mid]) isame--;
int ln = lft, rn = mid + 1;
for(i = lft; i <= rht; i++) {
if(i == lft) { // 初始一个子树。
t[p].num[i] = 0;
} else { // 初始区间下一个节点。
t[p].num[i] = t[p].num[i-1];
}
if(t[p].val[i] < sorted[mid]) {
t[p].num[i]++;
t[p+1].val[ln++] = t[p].val[i];
}else if(t[p].val[i] > sorted[mid]) {
t[p+1].val[rn++] = t[p].val[i];
}else {
if(same < isame) {
same++;
t[p].num[i]++;
t[p+1].val[ln++] = t[p].val[i];
}else {
t[p+1].val[rn++] = t[p].val[i];
}
}
}
build(lft, mid, p+1);
build(mid+1, rht, p+1);
}
int ans;
void query(int a, int b, int k, int p, int lft, int rht) {
if(a>b)
return;
if(lft == rht)//只有一个元素,而且等于查找的数,要特殊处理下
{
//printf("p=%d\n",t[p].val[a]);
if(t[p].val[a]<=k)
{
ans++;
return;
}
}
int s, ss, b2, bb, mid = md(lft, rht),sss;
if(a == lft) {
s = t[p].num[b];
ss = 0;
} else {
s = t[p].num[b] - t[p].num[a-1];
ss = t[p].num[a-1];
}
if(sorted[mid]>k) { // 进入左孩子,同时更新区间端点值。
a = lft + ss;
b = lft + ss + s - 1;
query(a, b, k, p+1, lft, mid);
} else {
//printf("a=%d\n",a);
ans+=s;
bb = a - lft - ss;
b2 = b - a + 1 - s;
a = mid + bb + 1;
b = mid + bb + b2;//如果b2=0时,a>b,即区间会划分到空,下次递归跳出
query(a, b, k,p+1, mid+1, rht);
}
}
int main()
{
int i,j,x,y;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%d",&t[1].val[i]);
sorted[i]=t[1].val[i];
}
sort(sorted+1,sorted+1+n);
build(1,n,1);
while(m--)
{
ans=0;
scanf("%d%d%d",&x,&y,&k);
query(x,y,k,1,1,n);
printf("%d\n",ans);
}
}
return 0;
}