Petya and Array

 Petya and Array

 

题意:给你n个数,问有多少个区间的和的值小于t

分析:区间和问题,常常用到前缀和来进行预处理,所以先预处理出前缀和数组sum

sum[i]代表前i个数的和,那么sum[i]的贡献就是, 当i<k<=n时,存在多少个k,使sum[k]<t+sum[i],也就是求在[i+1,n]中,小于t+sum[i]的数有多少。

所以我们可以类比于询问逆序对方法,使用权值线段树来解决,这里因为数的范围较大,首先需要进行离散化处理。

AC_Code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 2e5+10;
 5 #define rep(i,first,last) for(int i=first;i<=last;i++)
 6 #define dep(i,first,last) for(int i=first;i>=last;i--)
 7 vector<ll>v;
 8 int tree[maxn<<3];
 9 ll sum[maxn],a[maxn],n,t,ans;
10 
11 int getid(ll x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
12 void updata(int rt,int l,int r,int pos){
13     if( l==r ){
14         tree[rt]++;
15         return ;
16     }
17     int mid=(l+r)>>1;
18     if( pos>mid ) updata(rt<<1|1,mid+1,r,pos);
19     else updata(rt<<1,l,mid,pos);
20     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
21 }
22 
23 ll query(int rt,int l,int r,int val){
24     if( l==r ) return tree[rt];
25     int mid=(l+r)>>1;
26     ll f=0;
27     if( val>mid ) return f+=tree[rt<<1]+query(rt<<1|1,mid+1,r,val);
28     else return f+=query(rt<<1,l,mid,val);
29     return f;
30 }
31 
32 int main(){
33     scanf("%lld%lld",&n,&t);
34     rep(i,1,n){
35         scanf("%lld",&a[i]);
36         sum[i]=sum[i-1]+a[i];
37         v.push_back(sum[i]);
38     }
39     if(n==1){
40         if( a[1]<t ) printf("1
");
41         else printf("0
");
42         return 0;
43     }
44     rep(i,0,n){         //注意从零开始
45         ll x=sum[i]+t;
46         v.push_back(x-1);
47     }
48     sort(v.begin(),v.end());
49     v.erase(unique(v.begin(),v.end()),v.end());
50     int len=v.size();
51     updata(1,1,len,getid(sum[n]));
52     dep(i,n-1,0){       //注意到0截止
53         ll x=sum[i]+t;
54         ans+=query(1,1,len,getid(x-1));
55         updata(1,1,len,getid(sum[i]));
56     }
57     printf("%lld
",ans);
58     return 0;
59 }
原文地址:https://www.cnblogs.com/wsy107316/p/12334806.html