\(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. ADO.Net学习总结

    一.讲述6个ADO.NET中的常用对象: Connection对象Command对象DataReader对象DataAdapter对象DataSet对象DataTable对象DataRow对象Data ...

  2. 基于Windows 配置 nginx 集群 & 反向代理

    1.下载 nginx 下载页面 : http://nginx.org/en/download.html 具体文件: http://nginx.org/download/nginx-1.7.0.zip ...

  3. We could not complete your iTunes Store request

    We could not complete your iTunes Store request.An unknown error occurred(502). There was an error i ...

  4. FDStoredProc 存储过程控件 强

    //FireDAC FDStoredProc1->StoredProcName = "myReport1"; FDStoredProc1->Prepare(); FDS ...

  5. solr dismax与edismax的参数列表

    dismax q.alt qf (Query Fields) mm (Minimum 'Should' Match) pf (Phrase Fields) ps (Phrase Slop) qs (Q ...

  6. ios图片的拉伸

    http://blog.csdn.net/q199109106q/article/details/8615661 - (UIImage *)stretchableImageWithLeftCapWid ...

  7. 两个链表的交叉 · Intersection of Two Linked Lists

    [抄题]: Write a program to find the node at which the intersection of two singly linked lists begins. ...

  8. 逆序对 分治nlogn

    定义:A是包含n个元素的有序序列{a1,a2 … an},若ai > aj 且 i < j ,则称 (ai , aj)是A的一个逆序对.求逆序对是指求出A中存在逆序对的数量. 这个算法是归 ...

  9. a标签href="javascript:;"

    //点击a链接,执行一段js代码 <!DOCTYPE html> <html> <head> <title></title> </he ...

  10. 回答了这四个问题,你就可以打造最佳App首页

    如果把手机APP比作人的话,首页就是脸面了.首页是一款产品的大门,好的开头就是成功的一半. 调查表示,26%的手机APP的平均使用次数只有一次.对首次使用产品的用户而言,首页的好坏关乎到用户对该产品的 ...