转载请注明出处,谢谢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; }