\(Description\)

给你一个序列,每次询问一个区间,求其所有子区间的最小值之和

\(Solution\)

这里要用莫队算法

首先令\(val\)数组为原序列

我们考虑怎么由一个区间\([l,r]\)到\([l,r+1]\)

我们发现新增加的区间为:

\[[l,r+1],[l+1,r+1],[l+2,r+1]...[r,r+1],[r+1,r+1]
\]

我们令\([l,r+1]\)内的最小值的位置为\(x\)

则\([l,r+1],[l+1,r+1]...[x-1,r+1],[x,r+1]\)的最小值都为\(val[x]\).

所以现在我们只需要考虑\([x+1,r+1],[x+2,r+1]...[r,r+1],[r+1,r+1]\)区间对答案的影响即可

用单调栈处理出\(pre[i]\)

\(pre[i]\)表示在\(i\)前第一个小于他的数的位置

这样子就可以知道左端点在\([pre_i,i]\)之间的数时,最小值都为\(i\)

求出这个就可以求出来\([x+1,r+1],[x+2,r+1]...[r,r+1],[r+1,r+1]\)的答案了

代码为:

for(int i=1;i<=n;i++) suml[i]=suml[pre[i]]+c[i]*(i-pre[i]);

有点类似前缀和,询问也差不多

具体直接见代码吧

\(Code\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
struct node {
int l,r,id,ans;
}a[100010];
int block[100010],c[500001],lg[500001];
bool cmp1(const node & a , const node & b ){
return block[a.l]==block[b.l]?a.r<b.r:a.l<b.l;
}
bool cmp2(const node & a , const node & b ){
return a.id<b.id;
}
int p,m,sqr,n,f[100010][60],suml[500001],sumr[500001];
int pre[500001],nex[500001];
stack<int> s;
int min(int a,int b){
return c[a]>c[b]?b:a;
}
void init() {
for(int i=1; i<=n; i++)
f[i][0]=i;
for(int i=1; i<=lg[n]; i++)
for(int j=1; j<=n-(1<<i)+1; j++)
f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
for(int i=1;i<=n;i++){
while(!s.empty()&&c[s.top()]>c[i]) s.pop();
if(s.empty())
pre[i]=0,s.push(i);
else
pre[i]=s.top(),s.push(i);
}
while(!s.empty()){
p=s.top(),s.pop();
if(s.empty())
pre[p]=0;
else
pre[p]=s.top();
}
for(int i=n;i>=1;i--){
while(!s.empty()&&c[s.top()]>c[i]) s.pop();
if(s.empty())
nex[i]=n+1,s.push(i);
else
nex[i]=s.top(),s.push(i);
}
while(!s.empty()){
p=s.top(),s.pop();
if(s.empty())
nex[p]=n+1;
else
nex[p]=s.top();
}
for(int i=1;i<=n;i++)
suml[i]=suml[pre[i]]+c[i]*(i-pre[i]);
for(int i=n;i>=1;i--)
sumr[i]=sumr[nex[i]]+c[i]*(nex[i]-i);
}
int find(int a,int b) {
int k=lg[b-a+1];
return min(f[a][k],f[b-(1<<k)+1][k]);
}
int work(int l,int r){
int p=find(l,r);
return c[p]*(r-p+1)+sumr[l]-sumr[p];
}
int solve(int l,int r){
int p=find(l,r);
return c[p]*(p-l+1)+suml[r]-suml[p];
}
main(){
n=read(),m=read(),sqr=sqrt(n);
for(int i=1;i<=n;i++)
scanf("%lld",&c[i]),block[i]=i/sqr+1,lg[i]=log(i)/log(2);
for(int i=1;i<=m;i++)
scanf("%lld%lld",&a[i].l,&a[i].r),a[i].id=i;
sort(a+1,a+1+m,cmp1);
init();
int l=1,r=0,ans=0;
for(int i=1;i<=m;i++){
int x=a[i].l,y=a[i].r;
while(r<y) ans+=solve(l,r+1),r++;
while(l>x) ans+=work(l-1,r),l--;
while(r>y) ans-=solve(l,r),r--;
while(l<x) ans-=work(l,r),l++;
a[i].ans=ans;
}
sort(a+1,a+1+m,cmp2);
for(int i=1;i<=m;i++)
cout<<a[i].ans<<endl;
}

最新文章

  1. JS事件委托的原理和应用
  2. NSArray(二) 、 NSMutableArray 、 NSSet 、 NSMutableSet
  3. 搭建一个全栈式的HTML5移动应用框架(纯干货,亲!)
  4. [Linked List]Remove Duplicates from Sorted List II
  5. WPF使用RoutedCommand自己定义命令
  6. OO第一阶段总结
  7. 二次剩余Cipolla算法学习笔记
  8. idea上手
  9. 通过Loadruner对mysql数据库进行增删改查
  10. C#中四步轻松使用log4net记录本地日志(WPF有点小区别)
  11. 【codeforces 335E】 Counting Skyscrapers
  12. 【Java】 剑指offer(17) 在O(1)时间删除链表结点
  13. 【转】SQL Server 运行状况监控SQL语句
  14. JS_SINA股票接口
  15. iframe多层嵌套时获取元素
  16. Untracked Files Prevent Checkout move or commit them before checkout
  17. BootStrap框架引入文件
  18. NSInvocation 调用block clang代码转换c++
  19. 如何在VS2010环境下编译C++程序
  20. 洛谷 [CQOI2015]选数 解题报告

热门文章

  1. 372. Super Pow.txt
  2. 关闭 iTunes 自动同步
  3. Git--时光穿梭机之删除文件06
  4. 【334】Python Object-Oriented Programming
  5. 学习IIS &amp; MVC的运行原理 (转)
  6. testng参数化(提供测试数据)
  7. JSP九大对象
  8. Kubuntu中thunderbird最小化到任务栏
  9. 除了DFS的空间恒定为宽度*深度之外,其余都是宽度^深度次方
  10. 通过http流发送post请求