分析:离线线段树,把所有询问离线读入,然后按H从小到大排序。对于所有结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,最后就是一个区间求和。这题貌似也可以用划分树,树状数组等方法做。
#include<iostream> #include<algorithm> using namespace std; #define N 100005 struct Tree { int left,right,cnt; } TREE[N<<2]; struct Query { int l,r,h,id; bool operator<(const Query& q)const { return h<q.h; } } query[N]; struct Node { int pos,val; bool operator<(const Node& n)const { return val<n.val; } } node[N]; void Build(int root,int l,int r) { int m; TREE[root].cnt=0; TREE[root].left=l; TREE[root].right=r; if(l==r) return ; m=(l+r)>>1; Build(root<<1,l,m); //左子树 Build((root<<1)|1,m+1,r); //右子树 } void Update(int root,int pos) { int m; TREE[root].cnt++; if(TREE[root].left==TREE[root].right) return ; m=(TREE[root].left+TREE[root].right)>>1; if(pos<=m) Update(root<<1,pos); //左边 else Update((root<<1)|1,pos); //右边 } int QUERY(int root,int l,int r) { int m; if(TREE[root].left==l && TREE[root].right==r) return TREE[root].cnt; m=(TREE[root].left+TREE[root].right)>>1; if(r<=m) return QUERY(root<<1,l,r); //左边 else if(l>m) return QUERY((root<<1)|1,l,r); //右边 else return QUERY(root<<1,l,m)+QUERY((root<<1)|1,m+1,r); //中间 } int ans[N]; int main() { int t,T,n,q,i,j; ios::sync_with_stdio(false); cin>>T; t=0; while(T--) { cin>>n>>q; for(i=0;i<n;i++) { cin>>node[i].val; node[i].pos=i+1; } for(i=0;i<q;i++) { query[i].id=i; cin>>query[i].l>>query[i].r>>query[i].h; } sort(node,node+n); sort(query,query+q); Build(1,1,n); cout<<"Case "<<++t<<":"<<endl; for(i=0,j=0;i<q;i++) { while(j<n && node[j].val<=query[i].h) { Update(1,node[j].pos); j++; } ans[query[i].id]=QUERY(1,query[i].l+1,query[i].r+1); } for(i=0;i<q;i++) cout<<ans[i]<<endl; } return 0; }
时间: 2024-10-09 07:58:42