Petya and Array (权值线段树+逆序对)

本文介绍了一种高效算法,用于解决给定数组中区间和小于特定阈值t的个数问题。通过使用前缀和与逆序对的概念,结合自定义的数据结构和算法优化,实现了快速求解。文章提供了详细的代码实现与示例,帮助读者理解并应用此算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Petya and Array 

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

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Petya has an array aa consisting of nn integers. He has learned partial sums recently, and now he can calculate the sum of elements on any segment of the array really fast. The segment is a non-empty sequence of elements standing one next to another in the array.

Now he wonders what is the number of segments in his array with the sum less than tt. Help Petya to calculate this number.

More formally, you are required to calculate the number of pairs l,rl,r (lrl≤r) such that al+al+1++ar1+ar<tal+al+1+⋯+ar−1+ar<t.

Input

The first line contains two integers nn and tt (1n200000,|t|210141≤n≤200000,|t|≤2⋅1014).

The second line contains a sequence of integers a1,a2,,ana1,a2,…,an (|ai|109|ai|≤109) — the description of Petya's array. Note that there might be negative, zero and positive elements.

Output

Print the number of segments in Petya's array with the sum of elements less than tt.

Examples
input
5 4
5 -1 3 4 -1
output
5
input
3 0
-1 2 -3
output
4
input
4 -1
-2 1 -2 3
output
3
Note

In the first example the following segments have sum less than 44:

  • [2,2][2,2], sum of elements is 1−1
  • [2,3][2,3], sum of elements is 22
  • [3,3][3,3], sum of elements is 33
  • [4,5][4,5], sum of elements is 33
  • [5,5][5,5], sum of elements is 1

  参考博客 http://mamicode.com/info-detail-2452129.html

  找区间和小于t的个数,区间和的问题,一般用前缀和来做

  可以看成sum[i]>t+sum[k]的个数,i<k<=n。这样就变成了一个逆序对的问题

  

  1 #include<iostream>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<cstdio>
  8 #include<vector>
  9 #define maxn 500005
 10 #define lson l,mid,rt<<1
 11 #define rson mid+1,r,rt<<1|1
 12 typedef long long ll;
 13 using namespace std;
 14 
 15 vector<ll>v;
 16 ll n;
 17 ll a[maxn];
 18 ll sum[maxn];
 19 
 20 int tree[maxn<<3];
 21 
 22 int getid(ll x){
 23     return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
 24 }
 25 
 26 void pushup(int rt){
 27     tree[rt]=tree[rt<<1]+tree[rt<<1|1];
 28 }
 29 
 30 void build(int l,int r,int rt){
 31     if(l==r){
 32         tree[rt]=0;
 33         return;
 34     }
 35     int mid=(l+r)/2;
 36     build(lson);
 37     build(rson);
 38     pushup(rt);
 39 }
 40 
 41 void add(int L,int k,int l,int r,int rt){
 42     if(l==r){
 43         tree[rt]+=k;
 44         return;
 45     }
 46     int mid=(l+r)/2;
 47     if(L<=mid) add(L,k,lson);
 48     else add(L,k,rson);
 49     pushup(rt);
 50 }
 51 
 52 ll query(int L,int R,int l,int r,int rt){
 53     if(L<=l&&R>=r){
 54         return tree[rt];
 55     }
 56     int mid=(l+r)/2;
 57     ll ans=0;
 58     if(L<=mid) ans+=query(L,R,lson);
 59     if(R>mid) ans+=query(L,R,rson);
 60     return ans;
 61 }
 62 
 63 
 64 int main(){
 65 
 66     std::ios::sync_with_stdio(false);
 67     ll t;
 68     cin>>n>>t;
 69     for(int i=1;i<=n;i++){
 70         cin>>a[i];
 71     }
 72     v.push_back(t-1);
 73     for(int i=1;i<=n;i++){
 74         sum[i]=a[i]+sum[i-1];
 75         v.push_back(sum[i]);
 76         v.push_back(sum[i]+t-1);
 77     }
 78     if(n==1){
 79         if(a[1]<t){
 80             cout<<1<<endl;
 81         }
 82         else{
 83             cout<<0<<endl;
 84         }
 85     }
 86     else{
 87         sort(v.begin(),v.end());
 88         v.erase(unique(v.begin(),v.end()),v.end());
 89         int Size=v.size();
 90         build(1,Size,1);
 91         add(getid(sum[n]),1,1,Size,1);
 92         ll ans=0;
 93         for(int i=n-1;i>=1;i--){
 94             ans+=query(1,getid(sum[i]+t-1),1,Size,1);
 95             add(getid(sum[i]),1,1,Size,1);
 96         }
 97         ans+=query(1,getid(t-1),1,Size,1);
 98 
 99         cout<<ans<<endl;
100     }
101 
102 }
View Code

 

  

转载于:https://www.cnblogs.com/Fighting-sh/p/9719751.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值