题解:P15133 [ROIR 2026] 最后的滑动窗口问题
画一个平面,横轴是
考虑一个点
是斜距加,然后是求行区间和。
经典的,先把斜距差分成四个三角加:
然后三角加能拆成两个后缀加:
其中黄色的那个后缀加坐标系是斜的,所以点需要映射到
对
const int N = 2e5 + 5;
int n, q, a[N];
int stk[N], tp;
int pre[N], nxt[N];
struct Query { int l, r, i; };
VC<Query> e[N];
VC<PII> f[N];
ll ans[N];
struct fenwick {
ll c[N], d[N];
inline int lowbit(int x) {
return - x & x;
}
void add(int u, ll x) {
for(int i = u; i <= n * 2; i += lowbit(i)) {
c[i] += x;
d[i] += x * (u - 1);
}
}
ll query(int u) {
ll res = 0;
for(int i = u; i; i -= lowbit(i)) {
res += c[i] * u;
res -= d[i];
}
return res;
}
ll query(int l, int r) {
return query(r) - query(l - 1);
}
} t1, t2;
void solve() {
read(n, q);
FOR(i, 1, n) read(a[i]);
tp = 0; stk[tp] = 0;
FOR(i, 1, n) {
while(tp && a[stk[tp]] >= a[i]) tp --;
pre[i] = stk[tp];
stk[++ tp] = i;
}
tp = 0; stk[tp] = n + 1;
ROF(i, n, 1) {
while(tp && a[stk[tp]] > a[i]) tp --;
nxt[i] = stk[tp];
stk[++ tp] = i;
}
FOR(i, 1, n) {
f[1].eb(i, a[i]);
f[i - pre[i] + 1].eb(pre[i], - a[i]);
f[nxt[i] - i + 1].eb(i, - a[i]);
f[nxt[i] - pre[i] + 1].eb(pre[i], a[i]);
}
FOR(i, 1, q) {
INT(l, r, k);
e[k].pb({l, r - k + 1, i});
}
FOR(i, 1, n) {
for(auto [u, x] : f[i]) {
if(u < 1) continue;
t1.add(u + 1, - x);
t2.add(u + i, x);
}
for(auto h : e[i]) {
int l = h.l, r = h.r;
ans[h.i] += t1.query(l, r);
ans[h.i] += t2.query(l + i, r + i);
}
}
FOR(i, 1, q) print(ans[i]);
}