小红统计区间(hard) - 树状数组 + 离散化

题面

分析

存在负数不满足单调性,因此无法二分或者双指针,对于每一段符合条件的区间 l , r l, r l,r 都有 s u m r − s u m l − 1 > = k sumr - suml - 1 >= k sumr−suml−1>=k ,也就是 s u m l − 1 < = s u m r − k suml - 1 <= sumr - k suml−1<=sumr−k ,那么如果对于所有区间的前缀和来进行顺序存储,那么对于当前前缀和 s u m i sumi sumi ,可以去找小于等于 s u m i − k sumi - k sumi−k 的符合条件的前缀和有多少,但是前缀和的范围很大,所以就要进行离散化,将所有需要用到的前缀和都进行i离散化重新定下标,然后可以通过树状数组每次对遍历到的前缀和的位置加一,统计可以加上树状数组查询 s u m i − k sumi - k sumi−k 的结果,也就是这之前有多少个满足条件的前缀和。

代码
cpp 复制代码
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int N = 2e5 + 10;

ll a[N];
int tr[N];
map<ll, int> m;

void add(int u) {
    for(int i = u; i < N; i += (i & -i)) {
        tr[i] ++;
    }
    return ;
}

int query(int x) {
    int ans = 0;
    for(int i = x; i >= 1; i -= i & -i) ans += tr[i];
    return ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    ll k;
    cin >> n >> k;
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        a[i] += a[i - 1];
    }
    m[0] = 1;
    for(int i = 1; i <= n; i ++) {
        m[a[i]] = 1;
        m[a[i] - k] = 1;
    }
    int now = 1;
    for(auto &x: m) {
        x.second = now ++;
    }
    //for(auto j: m) cout <<j.first << ' ' <<  j.second << endl;
    ll ans = 0;
    add(m[0]);
    for(int i = 1; i <= n; i ++) {
        ans += query(m[a[i] - k]);
        add(m[a[i]]);
    }
    cout << ans << "\n";
}
相关推荐
晚风予卿云月17 小时前
【前缀和】一维前缀和 & 二维前缀和
数据结构·c++·算法
myjs99917 小时前
意识的两种类型
c++
林文韬32718 小时前
逐位二进制拼接 → 翻转 → 去头零 → 消邻重
算法
变量未定义~18 小时前
单点修改、区间求和(模板)、区间修改,单点查询(模板)
数据结构·算法
weixin_4684668518 小时前
SURF 图像特征提取算法新手实战指南
图像处理·人工智能·算法·机器视觉·surf·sift
Lumos_77718 小时前
程序的诞生
c++
basketball61618 小时前
C++ static_cast 完全解析
开发语言·c++
weixin_4684668518 小时前
支持向量机新手实战指南
人工智能·python·算法·机器学习·支持向量机
Lumbrologist19 小时前
【C++】零基础入门 · 第 12 节:模板与 STL 入门
开发语言·c++
weixin_4684668519 小时前
机器学习之决策树新手实战指南
人工智能·python·算法·决策树·机器学习·ai