题解 O
好题!
但数据是拿脚造的并且官方题解写得像shit一样
康不懂官方题解,于是学习了dalao做法
看了一年才看懂,于是下文是在试图解释dalao题解
首先能产生贡献的点一定是单调栈中的点,但每次爆扫单调栈复杂度显然不对
于是考虑单调栈中的每个元素对所有询问的贡献,这个可以只在弹栈时考虑
于是当栈中有两个元素 \(a_i>a_j\) 时,对于任意点 \(x\),若存在一个询问满足 \(x \in[l, r] \land t\geqslant x-i\)
则 \(i\) 会对每个合法的 \(x\) 产生 \(a_i-a_j\) 的额外贡献
发现并不好将 \(x\) 限制在一个区间内,于是可以前缀和做差,上面的限制变为了 \(x \leqslant r \land t\geqslant x-i\)
貌似是二维偏序的一个常见处理方法:将其画到平面直角坐标系里,于是变为询问 \((r, t)\) 左下方的点权和
剩下的扔张图跑路
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 400010
#define ll long long
// #define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, k, tot, m;
int sta[N], tem[N], top;
ll a[N], ans[N], pre[N];
struct node{int id, r, tim, op;}q[N<<3];
inline bool operator < (node a, node b) {return a.r-a.tim>b.r-b.tim;}
struct bit{
ll a[N];
inline void upd(int i, ll val, int lim) {for (; i<=lim; i+=i&-i) a[i]+=val;}
inline ll query(int i) {ll ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
void clear() {memset(a, 0, sizeof(a));}
}cnt, sum;
signed main()
{
freopen("o.in", "r", stdin);
freopen("o.out", "w", stdout);
n=read(); k=read(); tot=k<<1;
for (int i=1; i<=n; ++i) pre[i]=pre[i-1]+(a[i]=read());
for (int i=1; i<=k; ++i) {
q[i*2].tim=q[i*2-1].tim=read();
q[i*2-1].r=read()-1;
q[i*2].r=read();
q[i*2-1].op=-1; q[i*2].op=1;
q[i*2-1].id=q[i*2].id=i;
ans[i]=pre[q[i*2].r]-pre[q[i*2-1].r];
}
a[n+1]=(*max_element(a+1, a+n+1))+1;
for (int i=1; i<=n+1; ++i) {
while (top && a[sta[top]]<a[i]) {
int p=sta[top--];
if (!top) break;
q[++tot].r=p-1;
q[tot].tim=p-1-sta[top];
q[tot].op=a[sta[top]]-a[p];
q[++tot].r=i-1;
q[tot].tim=i-1-sta[top];
q[tot].op=a[p]-a[sta[top]];
}
sta[++top]=i;
}
sort(q+1, q+tot+1);
for (int i=1; i<=tot; ++i) tem[i]=q[i].r;
sort(tem+1, tem+tot+1);
m=unique(tem+1, tem+tot+1)-tem-1;
for (int i=1,rk; i<=tot; ++i) {
rk=lower_bound(tem+1, tem+m+1, q[i].r)-tem;
if (!q[i].id) {
cnt.upd(rk, q[i].op, m);
sum.upd(rk, 1ll*q[i].r*q[i].op, m);
}
else ans[q[i].id]+=1ll*(1ll*q[i].r*cnt.query(rk)-sum.query(rk))*q[i].op;
}
for (int i=1; i<=tot; ++i) tem[i]=q[i].tim;
sort(tem+1, tem+tot+1);
m=unique(tem+1, tem+tot+1)-tem-1;
cnt.clear(); sum.clear();
for (int i=tot,rk; i; --i) {
rk=lower_bound(tem+1, tem+m+1, q[i].tim)-tem;
if (!q[i].id) {
cnt.upd(rk, q[i].op, m);
sum.upd(rk, 1ll*q[i].tim*q[i].op, m);
}
else ans[q[i].id]+=1ll*(1ll*q[i].tim*cnt.query(rk)-sum.query(rk))*q[i].op;
}
for (int i=1; i<=k; ++i) printf("%lld\n", ans[i]);
return 0;
}