1. 程式人生 > >1042.D Petya and Array 字首 + 樹狀陣列

1042.D Petya and Array 字首 + 樹狀陣列

11.19.2018

1042.D Petya and Array
New Point

字首 + 樹狀陣列 :樹狀陣列逐個維護字首個數

Describe:

給你一個陣列,一個標記數,問你有多少區間[l,r]使得這個區間的和小於這個標記數值

Solution:

沒能想到

 

字首陣列 + 樹狀陣列快速查詢

記錄字首陣列sum[i],得到區間和為sum[i] - sum[j] < t,轉化為求sum[i] - t < sum[j],遍歷i,求取情況,然後利用樹狀陣列快速查詢符合的區間j的個數

樹狀陣列維護的是 sum[j],而且遍歷i[1,n]的時候j的範圍是

[0,i-1],所以對於一個新i,我們應該找到sum[i-1]在樹上的位置進行全域性更新,但是對於第一個i,更新sum[0] = 0即可,可以想到j0的時候表示a1 + …… + ai

Code

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 1e3;
ll sum[maxn];
ll f[maxn];
ll tree[maxn];
int n;
ll lowbit(ll x)
{
    return x & (-x);
}
void add(ll x)
{
    while(x <= n+1)
    {
        ++tree[x];
        x += lowbit(x);
    }
}
ll Get(ll x)
{
    ll ans = 0;
    while(x > 0)
    {
        ans += tree[x];
        x -=lowbit(x);
    }
    return ans;
}
int main()
{
    ll t;
    while(~scanf("%d %lld",&n,&t))
    {
        memset(sum,0,sizeof(sum));
        memset(tree,0,sizeof(tree));
        for(int i = 1;i <= n;++i)
        {
            scanf("%lld",&sum[i]);
            sum[i] += sum[i-1];
            f[i] = sum[i];
        }
        f[0] = 0;
        sort(f,f+n+1);
        ll ans = 0;
        for(int i = 1;i <= n;++i)
        {
            add(lower_bound(f,f+n+1,sum[i-1]) + 1 - f);
            ans += i - Get(lower_bound(f,f+n+1,sum[i] - t + 1) - f);
        }
        printf("%lld\n",ans);
    }
    return 0;
}