Problem Description
Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every
integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.
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<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<limits.h> 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<l1.val; } }p[maxn];//保存玛丽的原始位置和能跳的高度 struct node2{ int l,r; int id,h; bool operator<(const node2 l2)const{ return h<l2.h; } }q[maxn];//保存m次询问 int ans[maxn]; void pushup(int rs) { t[rs].cnt=t[rs<<1].cnt+t[rs<<1|1].cnt; } void build(int rs,int l,int r) { t[rs].l=l; t[rs].r=r; t[rs].cnt=0; if(l==r) return ; int mid=(l+r)>>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<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<limits.h> 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<l1.val; } }p[maxn];//保存玛丽的原始位置和能跳的高度 struct node2{ int l,r; int id,h; bool operator<(const node2 l2)const{ return h<l2.h; } }q[maxn];//保存m次询问 int ans[maxn]; int lowbit(int x) { return x&(-x); } void update(int x) { while(x<maxn) { cnt[x]++; x+=lowbit(x); } } int query(int x) { int s=0; while(x>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; }