题目大意:给定一个长为 n 的数组,求区间和于 [l,r] 间区间数
第一眼看到题目就可以想到前缀和,蛋柿枚举左右端点需要 O(n^2) 复杂度,面对 n\le 10^5 会炸
那我们不妨考虑数据结构优化,可以使用树,对于每个前缀和 cnt ,求出在 [cnt-r,cnt-l] 间前缀和的数量
但是为什么是 [cnt-r,cnt-l] 呢?推一下就可以了
l\le cnt_1-cnt_2\le r \\
=>l-cnt_1\le -cnt_2\le r-cnt_1\\
=>cnt_1-r\le cnt_2\le cnt_1-l
所以只需要维护一棵树,支持查询 cnt-l,cnt-r 的排名即可,
刚好C++的 pb_ds 库中有着这么一棵树(不知道pb_ds的点这里)
所以只要直接使用即可(当然你要手打我也拦不住你)
核心:
//main
int n, l, r;
cin >> n >> l >> r;
Tree tree;
tree.insert(cnt);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
cnt += a[i];
ans += tree.order_of_key(cnt - l) - tree.order_of_key(cnt - r);
tree.insert(cnt);
}
cout << ans;
struct cmp
{
bool operator()(const int &a, const int &b) const
{
return a < b;
}
};
这里不一次性插入完前缀再查询的原因是可能让之前的前缀匹配到之后的前缀(如设
S_1=\sum^r_{i=1}a_i\hspace{1cm} S_2=\sum^{r+k}_{i=1}a_i
但 S_2=S_1-l ,这样显然是会不合理地计算的(计算了一个倒着的区间 ,即 l>r )
)