Codeforce 1042 D. Petya and Array(树状数组、前缀和)

题目链接
省赛选拔学长说是CF的原题,赛后得知学长是用树状数组写的,补了一个树状数组的代码。

题意

N N 个数,问一共有多少个连续区间满足区间和小于 M M

思路

记录每个数的前缀和 s o r t sort 之后,枚举区间的起始位置找到前缀和小于 M + p r e M + pre 的个数(设当前区间起始为i,满足条件的区间== L a s t p r e N o w p r e < M Lastpre - Nowpre < M )Lastpre:后面的前缀和,Nowpre:当前的前缀和

比赛的时候tony5t4rk用vector删除元素T掉了,后来splay优化过了(tql).

#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
const int maxn = 2e5 + 7;

int num[maxn];
void Add(int x, int d) {
    x++;
    while (x < maxn) {
        num[x] += d;
        x += lowbit(x);
    }
}
int Sum(int x) {
    x++;
    int sum = 0;
    while(x > 0) {
        sum += num[x];
        x -= lowbit(x);
    }
    return sum;
}

int main () {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    
    int n;
    LL m;
    while (cin >> n >> m) {
        mem(num, 0);
        vector<LL> a(n), b(n);
        for (int i = 0; i < n; ++i) {
            cin >> a[i];
            if (i) a[i] += a[i-1];
            b[i] = a[i];
        }
        sort(b.begin(), b.end());
        b.resize(unique(b.begin(), b.end()) - b.begin());
        for (LL it : a) {
            Add(lower_bound(b.begin(), b.end(), it) - b.begin(), 1);
        }
        LL ans = 0, sum = 0;
        for (int i = 0; i < n; ++i) {
            if (i) sum = a[i-1];
            LL tmp = Sum(lower_bound(b.begin(), b.end(), sum+m) - b.begin()-1);
            ans += tmp;
            Add(lower_bound(b.begin(), b.end(), a[i]) - b.begin(), -1);
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/89060653