标签:
n个数,m次询问
每次询问在 l-r区间内的 大小范围的在 a-b之间的数字个数
先将原数组排序
做两遍线段树
第一次对m次询问的b升序排列,每次插入所有小于等于b的数字,然后线段树查询在区间 l-r范围内的数字个数,记录在ans[i].r
第二次对m次询问的a升序排列,每次插入所有小于a的数字,然后线段树查询在区间l-r范围内的数字个数,记录在ans[i].l
最后每次询问的答案即为 ans[i].r-ans[i].l;
#include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct A { int x,id; }a[50010]; struct B { int l,r,a,b,id; }b[50010]; struct node { int l,r,x; }data[200010]; struct Ans { int l,r; }ans[50010]; bool cmp_a(A a,A b) { return a.x<b.x; } bool cmp_bb(B a,B b) { return a.b<b.b; } bool cmp_ba(B a,B b) { return a.a<b.a; } void build(int l,int r,int k) { int mid; data[k].l=l; data[k].r=r; data[k].x=0; if (l==r) return ; mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); } void updata(int x,int k) { data[k].x++; if (data[k].l==data[k].r) return ; if (x<=data[k*2].r) updata(x,k*2); else updata(x,k*2+1); } int query(int l,int r,int k) { int mid; if (data[k].l==l && data[k].r==r) return data[k].x; mid=(data[k].l+data[k].r)/2; if (r<=mid) return query(l,r,k*2); else if (l>mid) return query(l,r,k*2+1); else return query(l,mid,k*2)+query(mid+1,r,k*2+1); } int main() { int t,Case,n,m,i,mark; scanf("%d",&t); Case=1; while (t--) { scanf("%d%d",&n,&m); for (i=1;i<=n;i++) { scanf("%d",&a[i].x); a[i].id=i; } sort(a+1,a+1+n,cmp_a); a[n+1].x=1000000001; for (i=1;i<=m;i++) { scanf("%d%d%d%d",&b[i].l,&b[i].r,&b[i].a,&b[i].b); b[i].id=i; } build(1,n,1); sort(b+1,b+1+m,cmp_bb); mark=1; for (i=1;i<=m;i++) { while (a[mark].x<=b[i].b) updata(a[mark++].id,1); ans[b[i].id].r=query(b[i].l,b[i].r,1); } build(1,n,1); sort(b+1,b+1+m,cmp_ba); mark=1; for (i=1;i<=m;i++) { while (a[mark].x<b[i].a) updata(a[mark++].id,1); ans[b[i].id].l=query(b[i].l,b[i].r,1); } printf("Case #%d:\n",Case++); for (i=1;i<=m;i++) printf("%d\n",ans[i].r-ans[i].l); } return 0; }
标签:
原文地址:http://blog.csdn.net/u011932355/article/details/45038345