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
题意:给你N个数,M次询问,每次输入一个区间和一个高度,求这个区间内不超过这个高度的数的个数。
算法:主席树
代码:
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> using namespace std; const int maxn = 1e5+5; struct node { int l, r, s; }tree[maxn * 40]; vector<int> v; int a[maxn]; int cnt; int root[maxn]; void build(int &cur, int l, int r) { cur = ++cnt; tree[cur].s = 0; if(l == r) { return; } int mid = (l + r) >> 1; build(tree[cur].l, l, mid); build(tree[cur].r, mid + 1, r); } int getId(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; } void update(int l, int r, int x, int &y, int pos) { y = ++cnt; tree[y] = tree[x]; tree[y].s++; if(l == r) { return; } int mid = (l + r) >> 1; if(pos <= mid) { update(l, mid, tree[x].l, tree[y].l, pos); } else { update(mid + 1, r, tree[x].r, tree[y].r, pos); } } int query(int l, int r, int x, int y, int h) { if(l == r) { return tree[y].s - tree[x].s; } int mid = (l + r) >> 1; int ans = 0; //存储小于该高度的数的数量 if(h <= mid) { ans += query(l, mid, tree[x].l, tree[y].l, h); } else { ans += tree[tree[y].l].s - tree[tree[x].l].s; //如果该数在右子树上,那么就需要把左子树上的数都加进去 ans += query(mid + 1, r, tree[x].r, tree[y].r, h); } return ans; } int main() { int T; int Case = 1; scanf("%d", &T); while(T--) { int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); v.push_back(a[i]); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); //build(root[0], 1, n); int size = v.size(); for(int i = 1; i <= n; i++) { update(1, size, root[i - 1], root[i], getId(a[i])); } printf("Case %d:\n", Case++); while(m--) { int left, right, k; scanf("%d %d %d", &left, &right, &k); left++; //此处记住需要加1,因为你的主席树是从1开始建立的 right++; int h = upper_bound(v.begin(), v.end(), k) - v.begin(); //找到第一个比k大的数的位置 int ans = 0; if(h > 0) { ans = query(1, size, root[left - 1], root[right], h); } cout << ans << endl; } } return 0; }