[ABC282Ex] Min + Sum

Problem Statement

You are given two sequences of integers of length $N$: $A = (A_1, A_2, \ldots, A_N)$ and $B = (B_1, B_2, \ldots, B_N)$.

Print the number of pairs of integers $(l, r)$ that satisfy $1 \leq l \leq r \leq N$ and the following condition.

  • $\min\lbrace A_l, A_{l+1}, \ldots, A_r \rbrace + (B_l + B_{l+1} + \cdots + B_r) \leq S$

Constraints

  • $1 \leq N \leq 2 \times 10^5$
  • $0 \leq S \leq 3 \times 10^{14}$
  • $0 \leq A_i \leq 10^{14}$
  • $0 \leq B_i \leq 10^9$
  • All values in the input are integers.

Input

The input is given from Standard Input in the following format:

$N$ $S$
$A_1$ $A_2$ $\ldots$ $A_N$
$B_1$ $B_2$ $\ldots$ $B_N$

Output

Print the answer.


Sample Input 1

4 15
9 2 6 5
3 5 8 9

Sample Output 1

6

The following six pairs of integers $(l, r)$ satisfy $1 \leq l \leq r \leq N$ and the condition in the problem statement: $(1, 1)$, $(1, 2)$, $(2, 2)$, $(2, 3)$, $(3, 3)$, and $(4, 4)$.


Sample Input 2

15 100
39 9 36 94 40 26 12 26 28 66 73 85 62 5 20
0 0 7 7 0 5 5 0 7 9 9 4 2 5 2

Sample Output 2

119

两个东西加起来要小于等于 \(S\),太烦了。考虑固定一个,弄另一个。

和这个东西几乎没有办法固定,那只能固定最小值了。

设区间 \([l,r]\) 的最小值为 \(x\),位置在 \(k\)。区间的最小值和位置可以用ST表求得

那么总所周知,所有跨过 \(k\) 的区间的最小值都是 \(x\)。设 \(B\) 的前缀和为 \(s\),那么此时要让 \(s_r-s_{l-1}+x\le S\),并满足 \(l\le k,r>k\)。要数满足要求的 \([l,r]\) 的个数。求得跨越 \(k\) 的区间数量后,递归到 \([l,k-1]\)\([k+1,r]\) 数数即可。

但是这个很难弄,至少几个变量很难 \(O(1)\) 的数出来。但是我们完全可以 \(O(\min(k-l,r-k))\) 的数出来。也就是只遍历分治出来的两个区间中的小区间。这样子的复杂度就可以达到 \(O(nlogn)\)。方法时在较小的那个区间枚举 \(l/r\),然后可以用二分求出有多少个区间符合要求。以枚举 \(l\) 为例,\(l\) 确定之后, \(s_{l-1}\)\(x\) 确定,要求有多少个区间满足 \(s_r\le S-x+s_{l-1}\),直接 lower_bound 就行了。

最终复杂度二分加只遍历小区间的 \(logn\),最终 \(O(nlog^2n)\).

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long LL;
int lg[N],n;
LL s,a[N],b[N],ans;
struct node{
	LL mn;
	int wh;
	node operator+(node x)
	{
		if(mn>x.mn)
			return (node){x.mn,x.wh};
		return (node){mn,wh};
	}
}st[N][25];
node ask(int l,int r)
{
	int k=lg[r-l+1];
	return st[l][k]+st[r-(1<<k)+1][k];
}
void solve(int l,int r)
{
//	printf("%d %d\n",l,r);
	if(l>r)
		return;
	node x=ask(l,r);
	if(x.wh-l<r-x.wh)
	{
		for(int i=l;i<=x.wh;i++)
		{
			int k=upper_bound(b+x.wh,b+r+1,b[i-1]+s-x.mn)-b-1;
			ans+=k-x.wh+1;
		}
	}
	else
	{
		for(int i=x.wh;i<=r;i++)
		{
			int k=lower_bound(b+l-1,b+x.wh,b[i]-s+x.mn)-b+1;
			ans+=x.wh-k+1;
		}
	} 
	solve(l,x.wh-1);
	solve(x.wh+1,r);
}
int main()
{
	scanf("%d%lld",&n,&s);
	for(int i=2;i<=n;i++)
		lg[i]=lg[i>>1]+1; 
	for(int i=1;i<=n;i++)
		scanf("%lld",a+i),st[i][0]=(node){a[i],i};
	for(int i=1;i<=lg[n];i++) 
		for(int j=1;j+(1<<i)-1<=n;j++)
			st[j][i]=st[j][i-1]+st[j+(1<<i-1)][i-1];
	for(int i=1;i<=n;i++) 
		scanf("%lld",b+i),b[i]+=b[i-1];
	solve(1,n);
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值