题目大意:
问数组满足条件的
l
−
r
l-r
l−r对数。
a
l
+
a
l
+
1
+
a
r
−
1
+
a
r
<
=
x
+
y
(
r
−
l
+
1
)
a_l+a_l+_1+a_r-_1+a_r<=x+y(r-l+1)
al+al+1+ar−1+ar<=x+y(r−l+1)
思路:
预处理
查询哪个区间,区间每个数都减去
y
y
y,故原数组都减去
y
y
y。
式子转变为
(
a
l
−
y
)
+
(
a
l
+
1
−
y
)
+
(
a
r
−
1
−
y
)
+
(
a
r
−
y
)
<
=
x
(a_l-y)+(a_l+_1-y)+(a_r-_1-y)+(a_r-y)<=x
(al−y)+(al+1−y)+(ar−1−y)+(ar−y)<=x
区间合查询处理一个前缀合。
再转化式子
s
u
m
[
r
]
<
=
x
+
s
u
m
[
l
−
1
]
sum[r]<=x+sum[l-1]
sum[r]<=x+sum[l−1]
r
>
=
l
,
r
>
l
−
1
r>=l,r>l-1
r>=l,r>l−1
如何计数(偏序问题)
式子化简后有两个条件,这是一个偏序问题。
对于这种只有两个条件的偏序一般都是通过排序先满足一个条件,再通过数据结构计数。
如果按下标排序
s
u
m
[
i
]
sum[i]
sum[i]本身比较大不好处理。
可以按
s
u
m
[
i
]
sum[i]
sum[i]的值升序排序。
这样排序有一个好处
对于一个
s
u
m
[
i
]
sum[i]
sum[i],需要把所有满足条件的(
s
u
m
[
?
]
<
=
x
+
s
u
m
[
i
]
sum[?]<=x+sum[i]
sum[?]<=x+sum[i])都加入数据结构中去,再查询坐标比
i
i
i大的个数。如果每个
i
i
i操作都要回退,时间复杂度难以保证。
升序排序可以发现
x
+
s
u
m
[
i
]
x+sum[i]
x+sum[i]是在一直变大的,加入数据结构的点只会变多,避免了回退操作。
查询比一个数或多或少实现的方法比较多。
很重要的一个点
处理的是前缀合,对于点
1
1
1,一定要把
s
u
m
[
0
]
=
0
sum[0]=0
sum[0]=0加入。
不加
d
e
b
u
g
debug
debug会很爽
Code
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
ll n,x,y,a[N],sum[N];
ll c[N];
struct PW{
ll val,id;
}b[N];
bool cmp(PW s1,PW s2){
if(s1.val!=s2.val){
return s1.val<s2.val;
}
else{
return s1.id<s2.id;
}
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int num){
if(x==0) return ;
for( ;x<=n+1;c[x]+=num,x+=lowbit(x));
}
ll query(int x){
ll re=0;
for( ;x>0;re+=c[x],x-=lowbit(x));
return re;
}
int main(){
guo312;
cin>>n>>x>>y; ll ans=0;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]-=y;
}
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
b[i].id=i,b[i].val=sum[i];
}
b[n+1].id=0,b[n+1].val=0;
sort(b+1,b+1+n+1,cmp); int now=1;
for(int i=1;i<=n+1;i++){
ll val=b[i].val+x;
while(now<=n&&b[now].val<=val){
add(b[now].id,1);
now++;
}
ans+=query(n)-query(b[i].id);
}
cout<<ans;
return 0;
}