codeforces 1042D - Petya and Array【树状数组+离散化】

题目:戳这里

题意:有n个数,问有多少个区间满足[L,R]内的和小于t。

解题思路:

[L,R]内的和小于t等价于sum[R]-sum[L-1]<t,将sum[L-1]左移,可以看出R与L的关系sum[R]<sum[L-1]+t。

因为n个数有正有负,所以前缀和sum[]没法直接二分,需要构造出一个有序的前缀和。这样就可以想到用树状数组来维护前缀和,考虑到树状数组维护前缀和,将R和L的关系改为sum[R]-t<sum[L-1]更好写一些(个人习惯,固定r,二分出l)。然后就转化成了常规的离散化树状数组的题目:遍历R,二分查找l,加入答案,更新树状数组。

附ac代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int inf = 0x3f3f3f3f;
 5 const int maxn = 2e5 + 10;
 6 #define lowbit(x) x&-x
 7 ll sum[maxn];
 8 ll a[maxn];
 9 ll c[maxn];
10 ll tem[maxn];
11 ll n, t;
12 void add(ll x, ll u) {
13     while(x <= n) {
14         c[x] += u;
15         x += lowbit(x);
16     }
17 }
18 ll getsum(ll x) {
19     ll res = 0;
20     while(x) {
21         res += c[x];
22         x -= lowbit(x);
23     }
24     return res;
25 }
26 int main() {
27     ll ans = 0;
28     scanf("%lld %lld", &n, &t);
29     for(ll i = 1; i <= n; ++i) {
30         scanf("%lld", &a[i]);
31         sum[i] = sum[i - 1] + a[i];
32         if(sum[i] < t) ++ans;
33     }
34     for(ll i = 1; i <= n; ++i) {
35         tem[i] = sum[i];
36     }
37     sort(tem + 1, tem + 1 + n);
38     for(ll i = 1; i <= n; ++i) {
39         ll x = lower_bound(tem + 1, tem + 1 + n, sum[i]) - tem;
40         ll y = upper_bound(tem + 1, tem + 1 + n, sum[i] - t) - tem;
41         ans += (i - 1 - getsum(y - 1));
42         add(x, 1ll);
43     }
44     printf("%lld\n", ans);
45     return 0;
46 }
View Code

 

posted @ 2018-11-06 20:38  euzmin  阅读(207)  评论(0编辑  收藏  举报