1. 程式人生 > >Codeforces Round #510 (Div. 2) D. Petya and Array(離散化+反向樹狀陣列)

Codeforces Round #510 (Div. 2) D. Petya and Array(離散化+反向樹狀陣列)

http://codeforces.com/contest/1042/problem/D

題意

給一個數組n個元素,求有多少個連續的子序列的和<t
(1<=n<=200000,abs(a[i])<=1e9)

思路

  • 將公式轉化以下,sum[r]-sum[l-1]<t 變成 sum[r]<sum[l-1]+t
  • 可以考慮遍歷每個r,先更新sum[r-1]+t,統計有多少滿足條件的sum[l-1],反向樹狀陣列維護即可

實現細節

  • 對於每個r是更新他的sum[r-1]
  • 因為要統計>sum[r]的數有多少,但是反向樹狀陣列是包含自己當前這個點的,所以要加一
  • 反向樹狀陣列的右邊界最好是陣列大小
#include<bits/stdc++.h>
#define M 400005
#define ll long long
using namespace std;
int tr[M];
int n,tot,i;
ll tp,p[M],x[M],ans,t;

int lowbit(int x){return x&(-x);}

void add(int x){
    while(x>0){
        tr[x]++;x-=lowbit(x);
    }
}

int qy(int x){
    x++;         //
    int ans=0;
    while(x<M){    //
       ans+=tr[x];x+=lowbit(x);
    }
   return ans;
} 
int fd(ll x){
    return lower_bound(p,p+tot,x)-p+1;
}
int main(){
    cin>>n>>t;
    tot=0;
    for(i=1;i<=n;i++){
        scanf("%lld",&x[i]);
        x[i]+=x[i-1];
        p[tot++]=x[i];
        p[tot++]=x[i]+t;
    }
    sort(p,p+tot);
    tot=unique(p,p+tot)-p;
    ans=0;
    for(i=1;i<=n;i++){
        add(fd(x[i-1]+t));   //
        ans+=qy(fd(x[i]));
        //cout<<ans<<endl;
    }
    cout<<ans;
}