[题解]CF1988E Range Minimum Sum
思路
如果没有删除操作,就是一个典中典。
直接枚举最小值 ,可以轻松 找到其所能管辖到的最大区间 。形式化地说,找到一个最小的 和一个最大的 ,使得 。
那么它对答案的贡献是 。
加入删除操作,也是差不多的做法,依旧是枚举最小值。可以按照删除元素的位置 进行如下分讨:
-
或 ,显然对答案无影响,贡献为 。
-
,在 左边的选择会少一种,贡献为 。
-
,在 右边的选择会少一种,贡献为 。
-
或 ,比较特殊的一种情况,当删除这个位置后, 对应新的区间范围可能变化,需要重新求解。可以直接利用 ST 表二分求解。
所有贡献都是连续的,直接差分计算即可。
Code
#include <bits/stdc++.h>
#define re register
#define fst first
#define snd second
#define ll long long
using namespace std;
typedef pair<int,int> pii;
const int N = 5e5 + 10,M = 24,inf = 1e9 + 10;
int n;
int arr[N],L[N],R[N],lg[N];
ll c[N];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
struct ST{
#define pot(x) (1 << x)
pii dp[N][M];
inline pii Add(pii a,pii b){
if (a.fst == b.fst) return {a.fst,min(a.snd,b.snd)};
else if (a.fst < b.fst) return {a.fst,min(a.snd,b.fst)};
else return {b.fst,min(a.fst,b.snd)};
}
inline void build(){
for (re int i = 2;i <= n;i++) lg[i] = lg[i >> 1] + 1;
for (re int i = 1;i <= n;i++) dp[i][0] = {arr[i],inf};
for (re int j = 1;j <= lg[n];j++){
for (re int i = 1;i + pot(j) - 1 <= n;i++) dp[i][j] = Add(dp[i][j - 1],dp[i + pot(j - 1)][j - 1]);
}
}
inline pii query(int l,int r){
int len = r - l + 1;
return Add(dp[l][lg[len]],dp[r - pot(lg[len]) + 1][lg[len]]);
}
#undef pot
}st;
inline void add(int l,int r,ll k){
if (l > r) return;
c[l] += k; c[r + 1] -= k;
}
inline void solve(){
n = read();
fill(c + 1,c + n + 5,0);
for (re int i = 1;i <= n;i++) arr[i] = read();
st.build();
for (re int i = 1;i <= n;i++) L[i] = R[i] = i;
for (re int i = 1;i <= n;i++){
while (L[i] > 1 && arr[L[i] - 1] > arr[i]) L[i] = L[L[i] - 1];
}
for (re int i = n;i;i--){
while (R[i] < n && arr[R[i] + 1] > arr[i]) R[i] = R[R[i] + 1];
}
for (re int i = 1;i <= n;i++){
int lnum = i - L[i] + 1,rnum = R[i] - i + 1;
add(1,L[i] - 2,1ll * lnum * rnum * arr[i]);
add(L[i],i - 1,1ll * (lnum - 1) * rnum * arr[i]);
add(i + 1,R[i],1ll * lnum * (rnum - 1) * arr[i]);
add(R[i] + 2,n,1ll * lnum * rnum * arr[i]);
if (L[i] > 1){
int l = 1,r = L[i] - 1;
while (l < r){
int mid = l + r >> 1;
if (st.query(mid,i).snd == arr[i]) r = mid;
else l = mid + 1;
}
int Lnum = i - l;
add(L[i] - 1,L[i] - 1,1ll * Lnum * rnum * arr[i]);
}
if (R[i] < n){
int l = R[i] + 1,r = n;
while (l < r){
int mid = l + r + 1 >> 1;
if (st.query(i,mid).snd == arr[i]) l = mid;
else r = mid - 1;
}
int Rnum = l - i;
add(R[i] + 1,R[i] + 1,1ll * lnum * Rnum * arr[i]);
}
}
for (re int i = 1;i <= n;i++) printf("%lld ",c[i] += c[i - 1]);
puts("");
}
signed main(){
int T; T = read();
while (T--) solve();
return 0;
}
作者:WaterSun
出处:https://www.cnblogs.com/WaterSun/p/18321473
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效