版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82926907
原题地址:http://codeforces.com/contest/1042/problem/D
题意:求所有 区间和小于 的这样的区间数量。
思路:从 到 的和小于 ,即 ,其中 是 的前缀和。实现的方法就是从前往后对于每一个 ,看在它前面有多少个大于 的前缀和。
这个过程用树状数组来维护,每次加入 ,然后查询 。这样可以保证每次查询 的时候,存在于树状数组中的必然是在i之前的前缀和。
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
int lowbit(int x) {
return x & -x;
}
ll n, t;
ll bit[maxn];
ll a[maxn], b[maxn];
void add(ll i, ll x) {//第i个位置+x
while (i <= (n + 1)) { //有n+1个前缀和数字
bit[i] += x;
i += lowbit(i);
}
}
ll query(ll x) {
ll ans = 0;
while (x) {
ans += bit[x];
x -= lowbit(x);
}
return ans;
}
int main() {
scanf("%lld%lld", &n, &t);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
a[i] += a[i - 1];
b[i] = a[i];
}
sort(b, b + 1 + n);//这样子是为了存b[0]=0;
ll cnt = 0;
int pos;
for (int i = 1; i <= n; i++) {
pos = lower_bound(b, b + 1 + n, a[i - 1]) - b + 1;
//不加1的话从0开始,树状数组的下标从1开始
add(pos, 1);
// pos = upper_bound(b, b + n + 1, a[i] - t ) - b ;//这个也行
pos = lower_bound(b, b + n + 1, a[i] - t + 1) - b;
/*
因为是sum[i-1]>sum[j]-t,是大于号
所以要么low_bound里面加1,要么upper_bound
*/
cnt += i - query(pos);
}
printf("%lld\n", cnt);
return 0;
}