题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:给出一个数列,若干询问,L,R,h,询问区间[L,R]中小于等于h的数字有多少个?
思路:比赛时我用的树状数组A的。后来发现有人用划分树,我是第一次看到划分树,就学习一下。但是查询的时候,划分树查询的是区间内第K小的数,而此题要小于等于某个值h的所有数字,所以二分K,将返回值与h比较即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX=100005;
struct Node
{
int L,R;
};
struct HuaFen_tree
{
Node a[MAX<<2];
int s[MAX],t[35][MAX],tot[35][MAX];
void input(int n)
{
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&s[i]);
t[1][i]=s[i];
}
sort(s+1,s+n+1);
}
void build(int dep,int u,int L,int R)
{
a[u].L=L;
a[u].R=R;
if(L==R) return;
int i,mid=(L+R)>>1;
int sameNum=mid-L+1;
for(i=L;i<=R;i++) if(t[dep][i]<s[mid]) sameNum--;
int LL=L,LR=mid,RL=mid+1,RR=R;
int Lnum=0,Rnum=0;
for(i=L;i<=R;i++)
{
if(i==L) tot[dep][i]=0;
else tot[dep][i]=tot[dep][i-1];
if(t[dep][i]<s[mid])
{
tot[dep][i]++;
t[dep+1][LL+Lnum]=t[dep][i];
Lnum++;
}
else if(t[dep][i]>s[mid])
{
t[dep+1][RL+Rnum]=t[dep][i];
Rnum++;
}
else
{
if(sameNum>0)
{
sameNum--;
tot[dep][i]++;
t[dep+1][LL+Lnum]=t[dep][i];
Lnum++;
}
else
{
t[dep+1][RL+Rnum]=t[dep][i];
Rnum++;
}
}
}
build(dep+1,u<<1,LL,LR);
build(dep+1,u<<1|1,RL,RR);
}
//在区间[a[u].L,a[u].R]这个区间中查找[L,R]中的第K大值
int query(int dep,int u,int L,int R,int K)
{
if(L==R) return t[dep][L];
int x,y,xx,yy,_L,_R,mid=(a[u].L+a[u].R)>>1;
if(L==a[u].L) x=0;
else x=tot[dep][L-1]; //x为[a[u].L,L-1]中分到左边的
y=tot[dep][R]-x; //y为[L,R]中分到左边的
if(y>=K)
{
_L=a[u].L+x;
_R=a[u].L+x+y-1;
return query(dep+1,u<<1,_L,_R,K);
}
else
{
xx=L-a[u].L-x; //xx是[a[u].L,L-1]中分到右边的
yy=R-L+1-y; //yy是[L,R]中分到右边的
_L=mid+1+xx;
_R=mid+1+xx+yy-1;
return query(dep+1,u<<1|1,_L,_R,K-y);
}
}
};
HuaFen_tree a;
int n,m,C,num=0;
int find(int sum,int h,int L,int R)
{
int low=1,high=sum,mid;
while(low<=high)
{
mid=(low+high)>>1;
if(a.query(1,1,L,R,mid)>h) high=mid-1;
else low=mid+1;
}
if(a.query(1,1,L,R,low)<=h) return low;
return high;
}
int main()
{
for(scanf("%d",&C);C--;)
{
scanf("%d%d",&n,&m);
a.input(n);
a.build(1,1,1,n);
int L,R,h,ans;
printf("Case %d:\n",++num);
while(m--)
{
scanf("%d%d%d",&L,&R,&h);
L++;
R++;
if(a.query(1,1,L,R,R-L+1)<=h) ans=R-L+1;
else if(a.query(1,1,L,R,1)>h) ans=0;
else ans=find(R-L+1,h,L,R);
printf("%d\n",ans);
}
}
return 0;
}