提供一种简单的 52 分做法。
查看原帖
提供一种简单的 52 分做法。
197648
封禁用户楼主2022/12/7 21:40

对于前 1313 个点,本题可以采用分治。

可以发现,对于区间 [x,y][x,y],令 mid=x+y2mid = \frac{x+y}{2} 答案一定有三种情况:

  1. xlrmid1x \le l \le r \le mid-1

  2. mid+1lrymid+1 \le l \le r \le y

  3. xlmidx \le l \le midmidrymid \le r \le y

可以发现对于 1122 两种情况可以分治解决,我们只需要求第三种情况,即经过 midmid 的区间答案。

我们求出以下数组:

maima_i 表示区间 [i,mid][i,mid] 或者区间 [mid,i][mid,i]aia_i 的最大值。

mbimb_i 表示区间 [i,mid][i,mid] 或者区间 [mid,i][mid,i]bib_i 的最大值。

tt 表示 mai×mbima_i \times mb_i 的后缀和。

saisa_i 表示 mama 数组的后缀和。

sbisb_i 表示 mbmb 数组的后缀和。

我们让 iimidmidrr 枚举右端点,同时在 midmid 左侧找出最后一个小于等于 maima_i 的数 map1ma_{p1},在 midmid 左侧找出最后一个小于等于 mbimb_i 的数 mbp2mb_{p2}

可以看出,在以区间 [p1,mid][p1,mid] 为左端点是 aa 的“势力范围”,此时最大值是 maima_i,否则最大值就是 saisa_ibb 同理。

p1p2p1 \le p2 时,即 aa 的“势力范围”不小于 bb 的,分三种情况讨论:

  1. 以区间 [l,p1][l,p1] 为左端点,此时完全没有被影响,贡献就是 tltp1t_l - t_{p1}

  2. 以区间 [p1+1,p2][p1+1,p2] 为左端点,此时被 aa 影响,但没有被 bb 影响,贡献就是 mai×(sbp1sbp2)ma_i \times (sb_{p1} - sb_{p2})

  3. 以区间 [p2+1,mid][p2+1,mid] 为左端点,此时被 aabb 同时影响,贡献就是 mai×mbi×(midp2+1)ma_i \times mb_i \times (mid-p2+1)

p1p1 大于 p2p2 时,情况类似,这里请读者自行分析。

5252 分代码:

#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define D(i,a,b) for(register int i=a;i>=b;--i)
#define ull unsigned long long
#define N 250010
int T,n,q;
ull sa[N],sb[N],ma[N],mb[N],t[N],a[N],b[N]; 
ull solve(int l,int r)
{
	if(l == r) return a[l] * b[l];
	if(r - l == 1) return a[l] * b[l] + a[r] * b[r] + max(a[l],a[r]) * max(b[l],b[r]); 
	int mid = (l + r) >> 1;
	ull ans = solve(l,mid-1) + solve(mid+1,r);
	ma[mid] = a[mid],mb[mid] = b[mid];
	F(i,mid+1,r) ma[i] = max(a[i],ma[i-1]),mb[i] = max(b[i],mb[i-1]);
	D(i,mid-1,l) ma[i] = max(a[i],ma[i+1]),mb[i] = max(b[i],mb[i+1]); 
	t[mid] = a[mid] * b[mid];
	D(i,mid-1,l)  t[i] = t[i+1] + ma[i] * mb[i];//t[] 表示最大值乘积的后缀和 
	sa[mid] = ma[mid],sb[mid] = mb[mid];
	D(i,mid-1,l) sa[i] = sa[i+1] + ma[i],sb[i] = sb[i+1] + mb[i];//sa[] sb[] 表示最大值的后缀和 
	int p1 = mid,p2 = mid;
	F(i,mid,r)
	{
		while(p1-1 >= l&&ma[p1-1] <= ma[i]) --p1;
		while(p2-1 >= l&&mb[p2-1] <= mb[i]) --p2;
		if(p1 <= p2)
		{
			ans += (mid - p2 + 1) * ma[i] * mb[i];//完全被影响 
			ans += ma[i] * (sb[p1] - sb[p2]);//只有 a[] 被影响 
			ans += t[l] - t[p1];//完全不影响 
		}
		else
		{
			ans += (mid - p1 + 1) * ma[i] * mb[i];//完全被影响
			ans += mb[i]  * (sa[p2] - sa[p1]);//只有 b[] 被影响
			ans += t[l] - t[p2];//完全不影响 
		}
	} 
	return ans;
}
int main()
{
	scanf("%d%d",&T,&n);
	F(i,1,n) scanf("%llu",&a[i]);
	F(i,1,n) scanf("%llu",&b[i]);
	scanf("%d",&q);
	while(q--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%llu\n",solve(l,r));
	}
    return 0;
}
2022/12/7 21:40
加载中...