传送门
题目大意: 询问区间中小于等于某个数的个数
思路: 没什么好说的,,, 就是一个模板题, 会求区间第k大, 就会求这个.
const int maxn = 1e5+5;
int n, m;
struct Tree {
int ls, rs, val; // 左右儿子的编号, 和维护的一个值.
}tre[maxn*40];
int idx, root[maxn];
int build(int l, int r) {
int nod = ++idx;
tre[nod].val = 0;
if (l == r) return nod;
int mid = (l + r) >> 1;
tre[nod].ls = build(l, mid);
tre[nod].rs = build(mid+1, r);
return nod;
}
int update(int pre, int l, int r, int pos, int v) {
int nod = ++idx;
tre[nod] = tre[pre]; tre[nod].val += v;
if (l == r) return nod;
int mid = (l + r) >> 1;
if (pos <= mid) tre[nod].ls = update(tre[pre].ls, l, mid, pos, v);
else tre[nod].rs = update(tre[pre].rs, mid+1, r, pos, v);
return nod;
}
int query(int ql, int qr, int l, int r, int pos) {
if (l == r) return tre[qr].val - tre[ql].val;
int mid = (l + r) >> 1;
int num = tre[tre[qr].ls].val - tre[tre[ql].ls].val;
if (pos > mid) {
return num + query(tre[ql].rs, tre[qr].rs, mid+1, r, pos);
}
else return query(tre[ql].ls, tre[qr].ls, l, mid, pos);
}
int a[maxn];
vector<int>ve;
int getid(int x) {
return upper_bound(ve.begin(), ve.end(), x) - ve.begin();
}
void solve() {
scanf("%d%d", &n, &m);
ve.clear(); idx = 0;
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", a+i);
ve.pb(a[i]);
}
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
root[0] = build(1, sz(ve)); //根节点
for (int i = 1 ; i <= n ; i ++) {
int pos = getid(a[i]);
root[i] = update(root[i-1], 1, sz(ve), pos, 1);
}
while (m--) {
int l, r, k; scanf("%d%d%d", &l, &r, &k);
++l; ++r; int pos = getid(k);
if (!pos) puts("0");
else {int tmp = query(root[l-1], root[r], 1, sz(ve), pos);
printf("%d\n", tmp);
}
}
}
如果是求小于等于某个数的数字之和, 那么把次数1改成相应的权值val[i]即可呀, 一样的~~~