对于前 13 个点,本题可以采用分治。
可以发现,对于区间 [x,y],令 mid=2x+y 答案一定有三种情况:
x≤l≤r≤mid−1
mid+1≤l≤r≤y
x≤l≤mid 且 mid≤r≤y
可以发现对于 1 和 2 两种情况可以分治解决,我们只需要求第三种情况,即经过 mid 的区间答案。
我们求出以下数组:
mai 表示区间 [i,mid] 或者区间 [mid,i] 中 ai 的最大值。
mbi 表示区间 [i,mid] 或者区间 [mid,i] 中 bi 的最大值。
t 表示 mai×mbi 的后缀和。
sai 表示 ma 数组的后缀和。
sbi 表示 mb 数组的后缀和。
我们让 i 从 mid 到 r 枚举右端点,同时在 mid 左侧找出最后一个小于等于 mai 的数 map1,在 mid 左侧找出最后一个小于等于 mbi 的数 mbp2。
可以看出,在以区间 [p1,mid] 为左端点是 a 的“势力范围”,此时最大值是 mai,否则最大值就是 sai,b 同理。
当 p1≤p2 时,即 a 的“势力范围”不小于 b 的,分三种情况讨论:
以区间 [l,p1] 为左端点,此时完全没有被影响,贡献就是 tl−tp1。
以区间 [p1+1,p2] 为左端点,此时被 a 影响,但没有被 b 影响,贡献就是 mai×(sbp1−sbp2)。
以区间 [p2+1,mid] 为左端点,此时被 a 和 b 同时影响,贡献就是 mai×mbi×(mid−p2+1)。
当 p1 大于 p2 时,情况类似,这里请读者自行分析。
52 分代码:
#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;
}