转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:给出一些数,查询区间内比H小的数有多少个
http://acm.hdu.edu.cn/showproblem.php?pid=4417
比赛的时候SB了,其实这题还是随便搞搞的。
哭~~~TLE了半天,调整姿势用离线线段树才过。
将所有的询问离线读入之后,按H从小到大排序。然后对于所有的结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,然后就是一个区间和。
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 1<<28
#define M 6000005
#define N 100005
#define maxn 300005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
using namespace std;
struct Tree{
int left,right,cnt;
}L[N*4];
struct Q{
int l,r,h,id;
bool operator <(const Q q1)const{
return h<q1.h;
}
}que[N];
struct Node{
int pos,val;
bool operator<(const Node n1)const{
return val<n1.val;
}
}nod[N];
void Bulid(int step,int l,int r){
L[step].left=l;
L[step].right=r;
L[step].cnt=0;
if(l==r) return;
int m=(l+r)/2;
Bulid(lson,l,m);
Bulid(rson,m+1,r);
}
void Update(int step,int pos){
L[step].cnt++;
if(L[step].left==L[step].right) return;
int m=(L[step].left+L[step].right)/2;
if(pos<=m) Update(lson,pos);
else Update(rson,pos);
}
int Query(int step,int l,int r){
if(L[step].left==l&&L[step].right==r)
return L[step].cnt;
int m=(L[step].left+L[step].right)/2;
// printf("%d %d %d %d\n",L[step].left,L[step].right,l,r);
if(r<=m) return Query(lson,l,r);
else if(l>m) return Query(rson,l,r);
else return Query(lson,l,m)+Query(rson,m+1,r);
}
int ans[N];
int main(){
int t,cas=0,n,q;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
for(int i=0;i<n;i++){
scanf("%d",&nod[i].val);
nod[i].pos=i+1;
}
for(int i=0;i<q;i++){
que[i].id=i;
scanf("%d%d%d",&que[i].l,&que[i].r,&que[i].h);
}
sort(nod,nod+n);
sort(que,que+q);
Bulid(1,1,n);
printf("Case %d:\n",++cas);
int k=0;
for(int i=0;i<q;i++){
while(k<n&&nod[k].val<=que[i].h){
Update(1,nod[k].pos);
k++;
}
ans[que[i].id]=Query(1,que[i].l+1,que[i].r+1);
}
for(int i=0;i<q;i++) printf("%d\n",ans[i]);
}
return 0;
}
其实还可以划分树做,哎
二分答案,然后判断区间的第K大数和H的关系
前者略快一点
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 1<<28
#define M 6000005
#define N 100005
#define maxn 300005
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
using namespace std;
struct Node{
int left,right;
int sum;
}L[N*4];
int sa[N],num[20][N],cnt[20][N];//sa中是排序后的,num记录每一层的排序结果,cnt[deep][i]表示第deep层,前i个数中有多少个进入左子树
void Bulid(int step,int l,int r,int deep){
L[step].left=l;
L[step].right=r;
if(l==r)
return;
int mid=(l+r)>>1;
int mid_val=sa[mid],lsum=mid-l+1;;
for(int i=l;i<=r;i++)
if(num[deep][i]<mid_val)
lsum--; //lsum表示左子树中还需要多少个中值
int L=l,R=mid+1;
for(int i=l;i<=r;i++){
if(i==l)
cnt[deep][i]=0;
else
cnt[deep][i]=cnt[deep][i-1];
if(num[deep][i]<mid_val||(num[deep][i]==mid_val&&lsum>0)){ //左子树
num[deep+1][L++]=num[deep][i];
cnt[deep][i]++;
if(num[deep][i]==mid_val)
lsum--;
}
else
num[deep+1][R++]=num[deep][i];
}
Bulid(2*step,l,mid,deep+1);
Bulid(2*step+1,mid+1,r,deep+1);
}
int Query(int step,int l,int r,int k,int deep){
if(l==r)
return num[deep][l];
int s1,s2; //s1为[L[step].left,l-1]中分到左子树的个数
if(L[step].left==l)
s1=0;
else
s1=cnt[deep][l-1];
s2=cnt[deep][r]-s1; //s2为[l,r]中分到左子树的个数
int m=(L[step].left+L[step].right)/2;
if(k<=s2) //左子树的数量大于k,递归左子树
return Query(lson,L[step].left+s1,L[step].left+s1+s2-1,k,deep+1);
int b1=l-1-L[step].left+1-s1; //b1为[L[step].left,l-1]中分到右子树的个数
int b2=r-l+1-s2; //b2为[l,r]中分到右子树的个数
return Query(rson,m+1+b1,m+1+b1+b2-1,k-s2,deep+1);
}
int slove(int l,int r,int h){
int ans=0,low=1,high=r-l+1,mid;
while(low<=high){
mid=(low+high)/2;
int tmp=Query(1,l,r,mid,0);
if(tmp<=h){ans=mid;low=mid+1;}
else high=mid-1;
}
return ans;
}
int main(){
int n,q,t,cas=0;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&sa[i]);
num[0][i]=sa[i];
}
sort(sa+1,sa+1+n);
Bulid(1,1,n,0);
printf("Case %d:\n",++cas);
while(q--){
int l,r,h;
scanf("%d%d%d",&l,&r,&h);
l++;r++;
printf("%d\n",slove(l,r,h));
}
}
return 0;
}