Input The first line follows an integer T, the number of test data.
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)
Output For each case, output "Case X: " (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query.
Sample Input
1 10 10 0 5 2 7 5 4 3 8 7 7 2 8 6 3 5 0 1 3 1 1 9 4 0 1 0 3 5 5 5 5 1 4 6 3 1 5 7 5 7 3
Sample Output
Case 1: 4 0 0 3 1 2 0 1 5 1
普通的线段树果断T成狗,故转向离线。
将砖块高度val和玛丽能跳的高度H都存起来,更新p[k].val<=q[i].h的,区间求和的时候就能保证当前更新的都是小于玛丽能跳的的高度。。。
#include#include #include #include #include typedef long long LL; using namespace std; const int maxn=1e5+10; struct tree{ int l,r; int cnt; }t[maxn<<2]; struct node1{ int val; int pos; bool operator<(const node1 l1)const{ return val >1; build(rs<<1,l,mid); build(rs<<1|1,mid+1,r); } void update(int rs,int pos) { t[rs].cnt++; if(t[rs].l==t[rs].r) return ; int mid=(t[rs].l+t[rs].r)>>1; if(pos<=mid) update(rs<<1,pos); else update(rs<<1|1,pos); } int query(int l,int r,int rs) { if(t[rs].l==l&&t[rs].r==r) return t[rs].cnt; int mid=(t[rs].l+t[rs].r)>>1; if(r<=mid) return query(l,r,rs<<1); else if(l>mid) return query(l,r,rs<<1|1); else return query(l,mid,rs<<1)+query(mid+1,r,rs<<1|1); } int main() { int t,n,m; int cas=1; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=n;i++) { scanf("%d",&p[i].val); p[i].pos=i; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h); q[i].id=i; } sort(p+1,p+1+n); sort(q+1,q+1+m); int k=1; for(int i=1;i<=m;i++) { while(k<=n&&p[k].val<=q[i].h) { update(1,p[k].pos); k++; } ans[q[i].id]=query(q[i].l+1,q[i].r+1,1); } printf("Case %d:\n",cas++); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }
另外树状数组也可以做。类似的单点更新和区间求和问题都可以用树状数组来写。
类似离线线段树的思想将节点和询问保存排序后依次更新,就能保证结果的正确性。
#include#include #include #include #include typedef long long LL; using namespace std; const int maxn=1e5+10; int cnt[maxn]; struct node1{ int val; int pos; bool operator<(const node1 l1)const{ return val 0) { s+=cnt[x]; x-=lowbit(x); } return s; } int main() { int t,n,m; int cas=1; scanf("%d",&t); while(t--) { memset(cnt,0,sizeof(cnt)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&p[i].val); p[i].pos=i; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h); q[i].id=i; } sort(p+1,p+1+n); sort(q+1,q+1+m); int k=1; for(int i=1;i<=m;i++) { while(k<=n&&p[k].val<=q[i].h) { update(p[k].pos); k++; } ans[q[i].id]=query(q[i].r+1)-query(q[i].l); } printf("Case %d:\n",cas++); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }