合适数对(树状数组 + 离散化)
4316. 合适数对.
求区间和不超过T得个数
思路
求区间和可以想到前缀和,数据范围大且个数少用离散化离散
前缀和为O(n^2)时间复杂度TLE
s[i] - s[i - k] < t , 移项可得 s[ i - k ] > s[ i ] - t
用树状数组动态维护s[ i ]的排名, 访问查询下标比 i 小的数(树状数组)小于s[ i ] - t 的个数, 并用总个数 i - query就是大于 s[ i ] - t的个数
样例输入:
5 4
5 -1 3 4 -1
样例输出:
5
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 400010;
int n;
LL m;
LL s[N], xs[N], cnt;
int tr[N];
int get(LL x)
{
int l = 1, r = cnt;
while (l < r)
{
int mid = l + r >> 1;
if (xs[mid] >= x) r = mid;
else l = mid + 1;
}
return r;
}
int lowbit(int x)
{
return x & -x;
}
void add(int x, int v)
{
for (int i = x; i < N; i += lowbit(i))
tr[i] += v;
}
int query(int x)
{
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += tr[i];
return res;
}
int main()
{
scanf("%d%lld", &n, &m);
//离散化
xs[ ++ cnt] = 0, xs[ ++ cnt] = -m;
for (int i = 1; i <= n; i ++ )
{
int x;
scanf("%d", &x);
s[i] = s[i - 1] + x;
xs[ ++ cnt] = s[i], xs[ ++ cnt] = s[i] - m;
}
//离散化排序讲当前所有元素转化为下标
sort(xs + 1, xs + cnt + 1);
//unique返回去重后的下一个位置 减去初始位置 - 1 -> 个数
cnt = unique(xs + 1, xs + cnt + 1) - xs - 1;
LL res = 0;
//l == r 的个数
add(get(0), 1);
for (int i = 1; i <= n; i ++ )
{
res += i - query(get(s[i] - m));
//个数 + 1
add(get(s[i]), 1);
}
printf("%lld\n", res);
return 0;
}