CF1042D - Petya and Array
Posted Luowaterbi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1042D - Petya and Array相关的知识,希望对你有一定的参考价值。
题目:
求满足区间和小于t的区间数量。
题解:
区间的数量可以转换成固定右端点,求满足条件的左端点的个数。
满足条件的区间
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]:
s
u
m
[
r
]
−
s
u
m
[
l
]
<
t
s
u
m
[
r
]
−
t
<
s
u
m
[
l
]
sum[r]-sum[l]<t\\\\ sum[r]-t<sum[l]
sum[r]−sum[l]<tsum[r]−t<sum[l]
会发现这是一个关于
s
u
m
sum
sum的单点修改(增加),区间(前缀)查询的问题。可以选择线段树、树状数组等方法解决。我选择用权值线段树。
首先,权值线段树求 x x x的rank本质上就是求前缀和。那我们可以转换一下问题,对于当前位置 i i i,有 i i i个前缀。其中有 ∑ j = 0 i − 1 ( s u m [ i ] − t ≥ s u m [ j ] ) \\sum_j=0^i-1(sum[i]-t\\geq sum[j]) ∑j=0i−1(sum[i]−t≥sum[j])个是不合法的。相减即可得到答案。
-
前缀和可能很大,但是数量很少,需要离散化(我没有用规范的离散化,我只适用快排之后用下标表示数字);
-
注意当区间长度为 i i i的时候,对应 s u m [ l = 0 ] = 0 sum[l=0]=0 sum[l=0]=0,这个要在开始循环之前加进去。用 s u m [ i ] sum[i] sum[i]表示前缀和时, s u m [ 0 ] sum[0] sum[0]正好是这个作用,所以离散化时 s u m sum sum数组长度不能是 n n n,而是 n + 1 n+1 n+1。但是由于离散化,update的时候对应的不再是 s u m [ 0 ] sum[0] sum[0]的下标 0 0 0,而是离散化后的位置!因为前缀和可能存在小于0的情况。
-
要求的是小于等于 s u m [ i ] − t sum[i]-t sum[i]−t的数量,那么lower_bound显然不合适:
- 因为当离散化后的 s u m sum sum没有正好等于 s u m [ i ] − t sum[i]-t sum[i]−t的数的时候,此时返回的下标比 s u m [ i ] − t sum[i]-t sum[i]−t大,那计算的时候不合法情况会增多;
- 由于我用的不是完全的离散化,当离散化后的 s u m sum sum有多个等于 s u m [ i ] − t sum[i]-t sum[i]−t的数时,lower_bound返回的是第一个的下标(离散后的值),就会导致计算时缺少情况。
-
选用upper_bound,对计算后的下标 − 1 -1 −1即可。
AC代码:
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#include <stack>
#include <cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=2e5+5;
const int mod=1e9+7;
const db eps=1e-6;
const db pi=acos(-1.0);
int n,m,tr[N<<2],a[N];
ll sum[N],t;
void update(int d,int l,int r,int x)
if(l==r)
tr[d]+=1;
return ;
int lc=d<<1,rc=lc|1,mid=(l+r)>>1;
if(x>mid) update(rc,mid+1,r,x);
else update(lc,l,mid,x);
tr[d]=tr[lc]+tr[rc];
ll query(int d,int l,int r,int x)
int lc=d<<1,rc=lc|1,mid=(l+r)>>1;
if(x<l) return 0;
if(tr[d]==0||x>=r) return tr[d];
if(x>mid) return tr[lc]+query(rc,mid+1,r,x);
else return query(lc,l,mid,x);
int main()
#ifndef ONLINE_JUDGE
freopen("D:\\\\work\\\\data.in","r",stdin);
#endif
cin>>n>>t;
rep(i,1,n)
cin>>a[i];
sum[i]=a[i]+sum[i-1];
// rep(i,1,n) sum[i+n]=sum[i]-t;
sort(sum,sum+n+1);//实际上是一个离散化的过程,前缀和值域太大,数量很少
ll res=0,ans=0;
// if(a[1]<t) ans++;
// update(1,1,n,lower_bound(sum+1,sum));
// update(1,0,n,0); 错误写法,这个0是为了保证只有自己一项的前缀和;但是0不一定在“0位置”
update(1,0,n,lower_bound(sum,sum+n+1,0)-sum);
rep(i,1,n)
res+=a[i];
int pos_t=upper_bound(sum,sum+n+1,res-t)-sum;
ans+=i;
ans-=query(1,0,n,pos_t-1);
int pos=lower_bound(sum,sum+n+1,res)-sum;
update(1,0,n,pos);
cout<<ans<<endl;
以上是关于CF1042D - Petya and Array的主要内容,如果未能解决你的问题,请参考以下文章