先考虑 $m=1$ 怎么做。设人要从 $l$ 走到 $r$,能量上限为 $x$。
假设当前人在 $i$,设最远能走到 $j$。不妨将 $a_r$ 看作 $0$,那么:
- 如果 $\exists k\in(i,j],a_i>a_k$,那么一定是在 $i$ 处买能量使得刚好能走到 $k$。
- 否则一定是在 $i$ 处买能量到上限,并走到 $k\in (i,j]$ 时 $a_k$ 最小的位置 $k$。
如果所有询问的 $x$ 都相等,那么我们可以预处理出每个 $i$ 会走到哪个 $k$,连一条边 $i\rightarrow k$。显然这会形成一棵内向树,询问时在树上倍增即可。
考虑每个 $i$ 在 $x$ 任意取值的情况下可能对应的 $k$。从后往前跑单调栈,所有被 $i$ 弹出的位置以及 $i$ 后面第一个满足 $a_i>a_j$ 的位置 $j$ 都会在 $x$ 取在某一段区间中时作为 $i$ 的出边,并且剩下的位置一定在任何时候都不可能作为 $i$ 的出边。
对于所有的 $i$,可能的位置数量的总和是 $O(n)$ 的。因此我们可以将询问离线下来,按照 $x$ 从小到大依次处理。
一种不需要脑子的方式是直接使用 LCT 动态维护内向树。时间复杂度 $O(n\log n)$。实际上在本题中它可以极大地减少思考量,不失为一种好方法。
这里我们再来介绍一种更为精妙的做法。
考虑确定一个 $x$,分析当前的边之间有什么特殊性质。
设 $d(u,v)$ 为从 $u$ 走到 $v$ 的距离。
这里给出一些关于边之间关系的结论,证明都是 trivial 的,这里不再赘述。
结论 $1$:对于任意两条边 $u_1\rightarrow v_1,u_2\rightarrow v_2$ 满足 $u_1< u_2$,有 $v_1\ge v_2$。
结论 $2$:对于任意两条边 $u_1\rightarrow v_1,u_2\rightarrow v_2$ 满足 $u_1< u_2,a_{u_2}\le a_{v_2}$,有 $u_2\ge v_1$。
结论 $2$ 启发我们将所有边 $u\rightarrow v$ 按照 $a_u>a_v$ 是否成立分为两类。根据之前的分析可以得到,对于 $u$ 的所有可能的出边 $u\rightarrow v$ 中最多只有一条满足 $a_u>a_v$,而这也形成了一棵内向树,设为 $T$。
设 $t$ 为满足 $d(t,r)\le x$ 且 $d(t,r)$ 最大的位置。
根据结论 $1,2$ 可以得到结论 $3$:对于所有不在 $T$ 中的边 $u\rightarrow v$,它在当前询问中被经过当且仅当 $u< t$。
因此我们可以对于所有不在 $T$ 中的边,维护相邻两条之间在 $T$ 上的距离。询问时相当于在序列上求区间和。
询问时从 $l$ 开始在 $T$ 中倍增,直到 $l$ 在 $T$ 中的父边当前不是 $l$ 的出边。然后通过上面所提到的方法求出所有不在 $T$ 中的边的贡献。最后再在 $T$ 中进行倍增求出最后一段的贡献即可。
实现时细节较多。
时间复杂度 $O(n\log n)$。
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define N 300005
#define ll long long
int n,m,tp,a[N],st[N],ps[N],L[N],R[N],mx[18][N],z[18][N];
ll s[N],ans[N],lim[18][N];struct Node {int l,r,id;ll x;}o[N*3];
struct Num
{
ll x,y;Num(ll _x=0,ll _y=0) {x=_x;y=_y;}
Num operator + (Num t) const {return Num(x+t.x,y+t.y);}
Num operator - (Num t) const {return Num(x-t.x,y-t.y);}
Num operator += (Num t) {return (*this)=(*this)+t;}
Num operator -= (Num t) {return (*this)=(*this)-t;}
}zero,w[N];
struct BitArray
{
Num bt[N];void upd(int x,Num vl) {for(;x<=n;x+=x&-x) bt[x]+=vl;}
Num qSm(int x) {Num res;for(;x;x-=x&-x) res+=bt[x];return res;}
}BIT;
bool cmp(Node x,Node y) {return x.x==y.x?x.id<y.id:x.x<y.x;}
Num f(int l,int r)
{
if(a[l]>a[r]) return Num((s[r]-s[l])*a[l],a[r]-a[l]);
return Num((s[r]-s[l])*a[r],0);
}
Num f1(int l,int r) {return Num((s[r]-s[l])*a[l],-a[l]);}
int findRt(int u) {return u==L[u]?u:L[u]=findRt(L[u]);}
int qMx(int l,int r)
{int t=31-__builtin_clz(r-l+1);return max(mx[t][l],mx[t][r-(1<<t)+1]);}
void upd(int l,int r)
{
int t=findRt(l),t1=t-1,t2=R[l+1];BIT.upd(l,zero-f(l,ps[l]));
if(a[l]>a[r])
{
L[l+1]=t;R[t]=t2;if(t1) BIT.upd(ps[t1],w[l]-w[t2]);
BIT.upd(ps[l],w[t2]-w[ps[l]]);
}
else
{
BIT.upd(ps[l],w[t2]-w[ps[l]]);
BIT.upd(r,w[r]-w[t2]);BIT.upd(l,f(l,r));
}ps[l]=r;
}
ll qry(int l,int r,ll x)
{
if(qMx(l,r-1)>x) return -1;
int t=lower_bound(s+1,s+n+2,s[r]-x)-s,t1;Num res=w[l];
for(int i=17;i>=0;--i) if(z[i][l]<=r && lim[i][l]<=x)
l=z[i][l];res-=w[l];
if(l<t) t1=findRt(t)-1,res+=BIT.qSm(t1)-BIT.qSm(l-1),l=ps[t1];res+=w[l];
for(int i=17;i>=0;--i) if(z[i][l]<=r && lim[i][l]<=x)
l=z[i][l];res+=f1(l,r)-w[l];return res.x+res.y*x;
}
int main()
{
scanf("%d %d",&n,&m);tp=m;st[++st[0]]=n+1;
for(int i=1;i<=n;++i) scanf("%d",&mx[0][i]),s[i+1]=s[i]+mx[0][i];
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n+1;++i) L[i]=R[i]=ps[i]=i;
for(int i=1;i<=m;++i)
scanf("%d %d %lld",&o[i].l,&o[i].r,&o[i].x),o[i].id=i;
for(int i=n;i;--i)
{
while(st[0] && a[i]<=a[st[st[0]]])
o[++tp]=(Node) {i,st[st[0]],0,s[st[st[0]]]-s[i]},--st[0];
z[0][i]=st[st[0]];lim[0][i]=s[z[0][i]]-s[i];
w[i]=w[z[0][i]]+f(i,z[0][i]);
o[++tp]=(Node) {i,z[0][i],0,s[z[0][i]]-s[i]};st[++st[0]]=i;
}z[0][n+1]=z[0][n+2]=n+2;
for(int i=1;i<=n;++i) BIT.upd(i,w[i]-w[i+1]);
for(int i=1;i<=17;++i)
{
for(int j=1;j+(1<<i)-1<=n;++j)
mx[i][j]=max(mx[i-1][j],mx[i-1][j+(1<<i-1)]);
for(int j=1;j<=n+2;++j)
{
z[i][j]=z[i-1][z[i-1][j]];
lim[i][j]=max(lim[i-1][j],lim[i-1][z[i-1][j]]);
}
}sort(o+1,o+tp+1,cmp);
for(int i=1;i<=tp;++i) if(o[i].id)
{
ans[o[i].id]=qry(o[i].l,o[i].r,o[i].x);
if(~ans[o[i].id]) ans[o[i].id]+=o[i].x*a[o[i].l];
}else upd(o[i].l,o[i].r);
for(int i=1;i<=m;++i) printf("%lld\n",ans[i]);return 0;
}