题目链接
题意:问区间和小于t的区间对数是多少?
思路:sum【j】<sum【i】+t,则问题就转化成了求【i+1,n】中小于sum【i】+t的个数,可以离散化后用权值线段树,树状数组二分也可以,不过不清楚权值线段树做法的时候v要push (sum+t)再离散化,留坑。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
struct cxk{
int l,r;
ll val;
}tree[maxn<<3];
vector<ll>v;
int n;
ll t,ans=0,a[maxn],sum[maxn];
void build(int l,int r,int x)
{
tree[x].l=l;tree[x].r=r;
if(l==r){
tree[x].val=0;return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
}
void update(int pos,int x)
{
tree[x].val++;
if(tree[x].l==tree[x].r) return ;
int mid=(tree[x].l+tree[x].r)>>1;
if(pos<=mid) update(pos,x<<1);
else update(pos,x<<1|1);
}
void query(int pos,int x)
{
if(tree[x].l==tree[x].r) return ;
int mid=(tree[x].l+tree[x].r)>>1;
if(mid>=pos) query(pos,x<<1);
else ans+=tree[x<<1].val,query(pos,x<<1|1);
}
int main()
{
scanf("%d%lld",&n,&t);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
v.push_back(sum[i]);
}
if(n==1)
{
printf("%d\n",a[1]<t?1:0);
return 0;
}
for(int i=1;i<=n;++i) v.push_back(sum[i]+t);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int size=v.size();
build(1,size,1);
update(lower_bound(v.begin(),v.end(),sum[n])-v.begin()+1,1);
for(int i=n-1;i>=0;--i)
{
query(lower_bound(v.begin(),v.end(),sum[i]+t)-v.begin()+1,1);
if(i>0) update(lower_bound(v.begin(),v.end(),sum[i])-v.begin()+1,1);
}
printf("%lld\n",ans);
}