数数(代码源打卡day.6)

本文分享了一道关于区间内小于等于特定值的计数问题,使用树状数组解决,展示了如何将前缀和思想应用到数据结构中,并介绍了如何维护和查询。通过实例代码解析了如何进行单点修改并求区间和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随便说点

这题开始时候想的是线段树(不知道为什么这两天的题我都想到要用线段树来做),后来想想是错的,但还是强行冲了一发,居然AAA了。后来出了一个后台数据,交到官方去了,不知道他们什么时候会加进去。

再讲一下题,这题用的是树状数组,当然也可以用线段树,算是让我这个数据结构白痴学习了一下数据结构的内容。

题意

给出一个数组,有qqq次询问,每次询问输出某个区间内小于等于xxx的数的数量。

题解

首先我们先明确一个前缀和的思想。题目问的是[l,r][l,r][l,r]区间内有多少数字符合条件,我们可以将其转化为前xxx个中有多少个点符合要求,然后通过sum(r)−sum(l−1)sum(r)-sum(l-1)sum(r)sum(l1)来得出答案。

然后是sum(x)sum(x)sum(x)怎么求?

sumsumsum是什么?我们可以认为是一种前缀和,那我们该如何维护这个前缀和呢?我们先把所有的值离散化,根据值的大小从小到大排序,同时我们把所有的询问的值也都从小到大排序,同时遍历两个数组,标记所有比当前询问小的值,因为询问是从小到大排序的,所以之前标记过的节点一定比当前询问要小。于是这个问题就被转换为了一个单点修改区间求和的题目,然后我们直接套树状数组板子就行了。

#include<bits/stdc++.h>
using namespace std;
int main() {
#ifdef ACM_LOCAL
    freopen("data.in", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _;
    cin >> _;
    while (_--) {
        int n, q;
        cin >> n >> q;
        vector<pair<int, int>> pir(n + 1);//存放数字
        for (int i = 1; i <= n; i++) cin >> pir[i].first, pir[i].second = i;
        sort(pir.begin() + 1, pir.end());
        struct matter {
            int l, r, h, t;
        };
        vector<matter> vec;//存放事件
        for (int i = 1; i <= q; i++) {
            int l, r, h;
            cin >> l >> r >> h;
            vec.push_back((matter) {l, r, h, i});
        }
        sort(vec.begin(), vec.end(), [](matter a, matter b) { return a.h < b.h; });
        vector<int> tree(n + 1);//树状数组
        vector<int> ans(q + 1);//存放答案
        vector<int> flag(n + 1);//单点修改
        auto lowbit = [](int x) -> int { return x & (-x); };
        auto add = [&n, &lowbit, &tree](int x, int k) -> void { for (int i = x; i <= n; i += lowbit(i)) tree[i] += k; };
        auto sum = [&lowbit, &tree](int x) -> int {
            int ans = 0;
            for (int i = x; i > 0; i -= lowbit(i)) ans += tree[i];
            return ans;
        };
        int p = 0;
        for (auto v: vec) {
            int l = v.l, r = v.r;
            int h = v.h, t = v.t;
            while (p < n && h >= pir[p + 1].first)
                add(pir[++p].second, 1);
            ans[t] = sum(r) - sum(l - 1);
        }
        for (int i = 1; i <= q; i++) cout << ans[i] << " ";
        cout << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值