标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5101 Accepted Submission(s): 2339
题目链接:HDU 4417
题意:给你n个数组成的序列求[L,R]中小于等于H的数有多少个,序列下标从0开始
本来对于一般的线段树就直接求和query(1,1,H)即可,但是这样子显然默认的根节点为1即对整颗线段树进行查询,而题目中给的是固定的一段区间,并非朴素线段树默认的的1,N。然后就可以用到主席树了,主席树可以有很多种的区间查询求区间第K大只是其中一种而已吧,这题就是求区间内的区间求和,好像听起来很别扭,就是对一个固定区间内部进行值域求和,本题就是进行区间查询(求和),过程和普通线段树非常相似,在注释中对比了一下普通线段树的姿势……
由于H可能过大,因此要离散化再用lowerbound把H等效为某一个离散化后的高度
代码:
#include <stdio.h> #include <bits/stdc++.h> using namespace std; #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define MID(x,y) ((x+y)>>1) const int N=1e5+7; struct seg { int lson,rson; int cnt; }; seg T[N*20]; int root[N],arr[N],tot; vector<int>vec; void init() { CLR(root,0); tot=0; vec.clear(); } void update(int &cur,const int &ori,const int &l,const int &r,const int &val) { cur=++tot; T[cur]=T[ori]; ++T[cur].cnt; if(l==r) return ; int mid=MID(l,r); if(val<=mid) update(T[cur].lson,T[ori].lson,l,mid,val); else update(T[cur].rson,T[ori].rson,mid+1,r,val); } int query(const int &S,const int &E,const int &l,const int &r,const int &x,const int &y) { if(x<=l&&r<=y)//l<=T[k].l&&T[k].r<=r return T[E].cnt-T[S].cnt;//return T[k].cnt; int mid=MID(l,r); if(y<=mid)//r<=T[k].mid return query(T[S].lson,T[E].lson,l,mid,x,y); else if(x>mid)//l>T[k].mid return query(T[S].rson,T[E].rson,mid+1,r,x,y); else return query(T[S].lson,T[E].lson,l,mid, x,mid)+query(T[S].rson,T[E].rson,mid+1,r, mid+1,y); } int main(void) { int T,n,m,i,l,r,h; scanf("%d",&T); for (int q=1; q<=T; ++q) { init(); scanf("%d%d",&n,&m); for (i=1; i<=n; ++i) { scanf("%d",&arr[i]); vec.push_back(arr[i]); } sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(),vec.end()),vec.end()); int R=vec.size(); for (i=1; i<=n; ++i) { arr[i]=lower_bound(vec.begin(),vec.end(),arr[i])-vec.begin()+1; update(root[i],root[i-1],1,R,arr[i]); } printf("Case %d:\n",q); for (i=0; i<m; ++i) { scanf("%d%d%d",&l,&r,&h); ++l; ++r; int indx=lower_bound(vec.begin(),vec.end(),h)-vec.begin()+1; //由于H可能过大因此只能找一个最接近的值indx来等效代替 if(vec[indx-1]!=h) --indx; printf("%d\n",indx? query(root[l-1],root[r],1,R,1,indx) : 0); } } return 0; }
HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)
标签:
原文地址:http://www.cnblogs.com/Blackops/p/5934177.html