题面传送门

这道题为什么我就没想出来呢/kk

对于每组询问 \([l,r]\),我们首先求出区间 \([l,r]\) 中最小值的位置 \(x\),这个可以用 ST 表实现 \(\mathcal O(n\log n)-\mathcal O(1)\) 维护,那么显然 \(\forall l'\in[l,x],r'\in[x,r],\min\limits_{t\in[l',r']}a_t=a_x\),产生的贡献为 \((r-x+1)(x-l+1)a_x\),于是我们只用计算 \([x+1,r],[l,x-1]\) 两个区间的贡献即可。

这个东西怎么计算呢?考虑枚举区间的右端点 \(R\),我们要计算 \([x+1,R],[x+2,R],\cdots,[R,R]\) 这 \(R-x\) 个区间的最小值之和,我们记 \(pre_x\) 为最大的满足 \(y<x,a_y\le a_x\) 的 \(y\)——\(pre_x\) 显然可以用单调栈在线性时间内求出。再记序列 \(p_1,p_2,\cdots,p_k\) 满足 \(p_0=0,p_k=R,\forall i\in[1,k],p_{i-1}=pre_{p_i}\) 的序列(说白了就是单调栈求完 \(pre_R\) 之后,栈底到栈顶位置上元素的下标依次形成的序列),那么显然 \(\forall i\in[1,k],l\in(p_{i-1},p_i]\) 都有 \(\min\limits_{t=l}^xa_t=a_{p_i}\),也就是说 \(a_{p_i}\) 位置会成为 \(p_i-p_{i-1}\) 个位置的最小值。如果我们记 \(f_R\) 为 \([1,R],[2,R],\cdots,[R,R]\) 的最小值之和,那么根据之前的推论有递推式 \(f_R=f_{pre_R}+(R-pre_R)a_R\),可线性求出。

这里还有一个问题,那就是我们要计算 \([x+1,R],[x+2,R],\cdots,[R,R]\) 的贡献 instead of \([1,R],[2,R],\cdots,[R,R]\),也就是说我们要减去 \([1,R],[2,R],\cdots,[x,R]\) 的贡献。这东西又怎么求呢?很明显 \(p\) 序列有一个性质就是必定 \(\exist id\in[1,k]\) 满足 \(p_{id}=x\),正确性显然,并且容易注意到 \(\forall l\in[1,x],\min\limits_{t=l}^Ra_t=\min\limits_{t=l}^xa_t\),也就是说 \([1,R],[2,R],\cdots,[x,R]\) 的贡献其实就是 \([1,x],[2,x],\cdots,[x,x]\),因此只需拿 \(f_R-f_x\) 就可以得到 \([x+1,R],[x+2,R],\cdots,[R,R]\) 的贡献。

故最终 \([x+1,r]\) 的贡献之和就是 \(\sum\limits_{R=x+1}^rf_R-f_x\),这个显然前缀和随便算一下就行了。求 \([l,x-1]\) 的贡献也同理。

时间复杂度 \(n\log n\),瓶颈在于 RMQ。

const int MAXN=1e5;
const int LOG_N=18;
const int INF=0x3f3f3f3f;
int n,qu,a[MAXN+5],pre[MAXN+5],nxt[MAXN+5];
ll fl[MAXN+5],fr[MAXN+5],gl[MAXN+5],gr[MAXN+5];
pii st[MAXN+5][LOG_N+2];
pii query(int l,int r){
int k=31-__builtin_clz(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
scanf("%d%d",&n,&qu);a[0]=a[n+1]=-INF;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
stack<int> stk;stk.push(0);
for(int i=1;i<=n;i++){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
pre[i]=stk.top();stk.push(i);
} while(!stk.empty()) stk.pop();
stk.push(n+1);
for(int i=n;i;i--){
while(!stk.empty()&&a[stk.top()]>=a[i]) stk.pop();
nxt[i]=stk.top();stk.push(i);
}
// for(int i=1;i<=n;i++) printf("%d %d\n",pre[i],nxt[i]);
for(int i=1;i<=n;i++) fl[i]=fl[pre[i]]+1ll*a[i]*(i-pre[i]),gl[i]=gl[i-1]+fl[i];
for(int i=n;i;i--) fr[i]=fr[nxt[i]]+1ll*a[i]*(nxt[i]-i),gr[i]=gr[i+1]+fr[i];
for(int i=1;i<=n;i++) st[i][0]=mp(a[i],i);
for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n;j++)
st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
while(qu--){
int l,r;scanf("%d%d",&l,&r);int p=query(l,r).se;
printf("%lld\n",1ll*a[p]*(p-l+1)*(r-p+1)+gr[l]-gr[p]-1ll*fr[p]*(p-l)+gl[r]-gl[p]-1ll*fl[p]*(r-p));
}
return 0;
}

最新文章

  1. coderforces #387 Servers(模拟)
  2. Myeclipse添加外部Tomcat出现启动故障的问题解决
  3. 中控考勤仪IFace302多线程操作时无法订阅事件
  4. xcode7 免费真机调试
  5. bug_ _ java.lang.IllegalArgumentException: pointerIndex out of range 问题的两种解决办法
  6. myeclipse激活+Aptana安装配置
  7. jQuery练习二球队移动
  8. properties 配置文件如何换行
  9. 关于xshell:Connection closed by foreign host
  10. UESTC 1584 Washi与Sonochi的约定【树状数组裸题+排序】
  11. [转]Angular开发(十八)-路由的基本认识
  12. jdbc,mysql 数据库BLOB返回值 [B 的问题
  13. 第一个Sprint
  14. 最小生成树kruskal模板
  15. Codeforces Round #394 (Div. 2) B. Dasha and friends 暴力
  16. Ubuntu安装ss
  17. Python入门系列教程(二)字符串
  18. HDU 5855 Less Time, More profit 最大权闭合子图
  19. MUI上传文件的方法
  20. 第08章-使用Spring Web Flow

热门文章

  1. python3去除行号
  2. 【UE4 C++ 基础知识】&lt;11&gt;资源的同步加载与异步加载
  3. 计算机网络传输层之TCP流量控制
  4. NOIP 模拟 八十五
  5. path-sum-ii leetcode C++
  6. nodejs:使用puppeteer在服务器中构建一个获取电影电视剧剧集的接口
  7. centos7 使用iptables
  8. 计算机网络漫谈之IP与子网掩码
  9. 升级JDK8的坎坷之路
  10. Linux常用命令和快捷键整理:(1)常用命令