Codeforces Round #510 (Div. 2) D. Petya and Array(离散化+反向树状数组)

时间:2023-03-09 13:44:27
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;
}