\(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;
}

「HNOI 2016」 序列的更多相关文章

  1. LOJ#3054. 「HNOI 2019」鱼

    LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...

  2. 【HNOI 2016】序列

    Problem Description 给定长度为 \(n\) 的序列:\(a_1, a_2, \cdots , a_n\),记为 \(a[1 \colon n]\).类似地,\(a[l \colon ...

  3. 「HNOI 2015」实验比较

    \(Description\) 有\(n\)个元素,对于每个元素\(x_i\)最多知道一个形如\(x_j < x_i\)或\(x_j=x_i\)的条件,问有多少合法的序列.合法的序列满足每个元素 ...

  4. loj 2292「THUSC 2016」成绩单

    loj 看着就很区间dp,所以考虑求\(f_{i,j}\)表示区间\([i,j]\)的答案.注意到贡献答案的方式是每次选一个连续段,拿走后剩下的段拼起来继续段,所以转移就考虑从最后一次选的方法转移过来 ...

  5. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

  6. 「HNOI 2019」白兔之舞

    一道清真的数论题 LOJ #3058 Luogu P5293 题解 考虑$ n=1$的时候怎么做 设$ s$为转移的方案数 设答案多项式为$\sum\limits_{i=0}^L (sx)^i\bin ...

  7. LOJ 2292 「THUSC 2016」成绩单——区间DP

    题目:https://loj.ac/problem/2292 直接 DP 很难做,主要是有那种 “一个区间内部有很多个别的区间” 的情况. 自己想了一番枚举 max-min 的最大限制,然后在该基础上 ...

  8. LOJ 2991 「THUSC 2016」补退选——trie+线段树合并或vector

    题目:https://loj.ac/problem/2291 想了线段树合并的做法.就是用线段树维护 trie 的每个点在各种时间的操作. 然后线段树合并一番,线段树维护前缀最大值,就是维护最大子段和 ...

  9. 2018.10.27 loj#2292. 「THUSC 2016」成绩单(区间dp)

    传送门 g[i][j][k][l]g[i][j][k][l]g[i][j][k][l]表示将区间l,rl,rl,r变成最小值等于kkk,最大值等于lll时的花费的最优值. f[i][j]f[i][j] ...

随机推荐

  1. halcon控制显示精度(精确到小数点后6位,精度足够了)

    实践应用 set_tposition (WindowHandle3,50, 50) write_string (WindowHandle3, '半径 D1=' +Ra[i]$'#f') set_tpo ...

  2. 迷你MVVM框架 avalonjs 1.3.3发布

    大家可以在仓库中看到,多出了一个叫avalon.observe的东西,它是基于Object.observe,dataset, Promise等新API实现.其中,它也使用全新的静态收集依赖的机制,这个 ...

  3. react-navigation 3.x版本的使用

    安装配置请看: react-navigation 3.x版本的安装以及react-native-gesture-handler配置 2.0以前版本: StackNavigator - 一次只渲染一个页 ...

  4. null与not null

    .not null CREATE TABLE `test` ( `col1` VARCHAR( ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NUL ...

  5. [SoapUI]怎样配置SoapUI运行的不同环境,并在Jenkins上面通过命令调用不用的环境

    配置SoapUI运行的不同环境 Groovy 脚本来控制environment 在Jenkins上面通过命令调用不用的环境 http://www.soapui.org/Test-Automation/ ...

  6. MyEclipse不能自动编译解决办法总结

    yEclipse在debug模式下,有时会碰到修改的文件无法自动编译的问题,以下的方法可以逐一尝试一下. 1.确保:Project->build automatically 已经被选上. 2.p ...

  7. nodejs顺序执行shell

    最近工作中需要用到nodejs编写脚本来顺序执行自动化测试用例,编写代码如下: var runCommand = function (command){ child_process.exec(comm ...

  8. 【工具推荐】ELMAH——可插拔错误日志工具(转)

    出处:http://www.cnblogs.com/liping13599168/archive/2011/02/23/1962625.html 今天看到一篇文章(构建ASP.NET网站十大必备工具( ...

  9. serialVersionUID的作用以及IDEA、Eclipse如何自动生成serialVersionUID

    说到serialVersionUID,首先要讲讲序列化. 序列化: 序列化可以将一个java对象以二进制流的方式在网络中传输并且可以被持久化到数据库.文件系统中,反序列化则是可以把之前持久化在数据库或 ...

  10. Converting HTML to PDF with pdfHTML

    https://itextpdf.com/itext7/pdfHTML pdfHTML 的一个例子 一个基本的例子将显示使用 pdfHTML.为此, 我们将使用下面的 HTML 和 CSS. < ...