bzoj 4540: [Hnoi2016]序列 莫队
题目:
给定长度为n的序列:a1,a2,…,an,记为a[1:n]。类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-
1,ar。若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列。现在有q个询问,每个询问给定两个数l和r,1≤l≤r
≤n,求a[l:r]的不同子序列的最小值之和。例如,给定序列5,2,4,1,3,询问给定的两个数为1和3,那么a[1:3]有
6个子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],这6个子序列的最小值之和为5+2+4+2+2+2=17。
题解:
首先这道题一看就是莫队.
然后就不会了...
校内胡测的第一题,可我不会啊...
只打了个暴力上去
首先这道题的难点在于拓展当前统计的答案区间.
也就是说:
在已经计算出来了区间\([l,r]\)的情况下,如何使其拓展到\([l,r+1]\)
首先我们知道枚举区间再计算区间的价值是不明智的
我们应该考虑枚举所有的元素,考虑其对区间的贡献.
在上面的拓展中,我们设\(left_i\)表示\(a_i\)前面第一个比它小的值的下标.
所以我们知道在拓展时新增的\((r+1) - l + 1\)个区间中
左端点在\([left_{r+1}+1,r+1]\)内的区间的价值一定都是\(a_{i+1}\)
所以现在我们的问题就是如何处理\([l,left_{r+1}]\)这段区间的贡献了.
我们设:\(f[i][j]\)表示处理区间\([i,j]\)所得到的贡献.
那么我们有:
\(f[i][j] = f[i][left_j] + (j - left_j)*a_{j}\)
我们发现实际上\(i\)只是限定了一个左端点而已.
所以我们查询区间\([l,r]\)时能够简单地取出\(f[l][r]\)
所以我们将\(f\)的第一个维度消去,即:
\(f[i] = f[left_i] + (i - left_i)*a_{i}\)
这样我们在查询区间\([l,r]\)时取出(f[r] - f[l-1])即可.
于是我们在莫队的时候再xjb乱搞一下就好了.
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(ll &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const ll maxn = 210010;
ll loger[maxn],minn[maxn][26],a[maxn];
ll minid[maxn][26];
inline void pre(ll n){
loger[1] = 0;
for(ll i=2;i<=n;++i){
loger[i] = loger[i-1];
if( i == (1 << loger[i]+1)) ++ loger[i];
}
for(ll i=n;i>=1;--i){
minn[i][0] = a[i];
minid[i][0] = i;
for(ll j=1;i + (1<<j) - 1 <= n;++j){
minn[i][j] = min(minn[i][j-1],minn[i+(1<<j-1)][j-1]);
if(minn[i][j] == minn[i][j-1]) minid[i][j] = minid[i][j-1];
if(minn[i][j] == minn[i+(1<<j-1)][j-1]) minid[i][j] = minid[i+(1<<j-1)][j-1];
}
}
}
inline ll query(ll l,ll r){
ll k = loger[r-l+1];
if(minn[l][k] < minn[r-(1<<k)+1][k]) return minid[l][k];
return minid[r-(1<<k)+1][k];
}
ll belong[maxn];
struct Node{
ll l,r,id;
bool friend operator < (const Node &a,const Node &b){
if(belong[a.l] == belong[b.l]) return a.r < b.r;
return belong[a.l] < belong[b.l];
}
}q[maxn];
ll anss[maxn],fl[maxn],fr[maxn];
ll sta[maxn],top;
inline void dp(ll n,ll *f){
sta[top = 1] = 0;
for(ll i=1;i<=n;++i){
while(a[sta[top]] > a[i]) -- top;
f[i] = (i - sta[top])*a[i] + f[sta[top]];
sta[++top] = i;
}
}
inline ll upd_R(ll l,ll r){
ll p = query(l,r+1);
return (p-l+1)*a[p] + fl[r+1] - fl[p];
}
inline ll upd_L(ll l,ll r){
ll p = query(l-1,r);
return (r-p+1)*a[p] + fr[l-1] - fr[p];
}
int main(){
ll n,Q;read(n);read(Q);a[0] = -(1LL<<60);
for(ll i=1;i<=n;++i) read(a[i]);
pre(n);dp(n,fl);reverse(a+1,a+n+1);//puts("reversed.");
dp(n,fr);reverse(a+1,a+n+1);reverse(fr+1,fr+n+1);
ll block = sqrt(n) + 1;
for(ll i=1;i<=n;++i) belong[i] = (i/block) + 1;
for(ll i=1;i<=Q;++i){
read(q[i].l);read(q[i].r);
q[i].id = i;
}sort(q+1,q+Q+1);
a[0] = 0;
ll L = 1,R = 1,ans = a[1];
for(ll i=1;i<=Q;++i){
while(R < q[i].r) ans += upd_R(L,R++);
while(R > q[i].r) ans -= upd_R(L,--R);
while(L > q[i].l) ans += upd_L(L--,R);
while(L < q[i].l) ans -= upd_L(++L,R);
anss[q[i].id] = ans;
}
for(ll i=1;i<=Q;++i){
printf("%lld\n",anss[i]);
}
getchar();getchar();
return 0;
}
bzoj 4540: [Hnoi2016]序列 莫队的更多相关文章
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...
- BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)
BZOJ 洛谷 ST表的一二维顺序一定要改过来. 改了就rank1了哈哈哈哈.自带小常数没办法. \(Description\) 给定长为\(n\)的序列\(A_i\).\(q\)次询问,每次给定\( ...
- BZOJ 4540 [Hnoi2016]序列 | 莫队 详细题解
传送门 BZOJ 4540 题解 --怎么说呢--本来想写线段树+矩阵乘法的-- --但是嘛--yali的机房太热了--困--写不出来-- 于是弃疗,写起了莫队.(但是我连莫队都想不出来!) 首先用单 ...
- [HNOI2016]序列(莫队,RMQ)
[HNOI2016]序列(莫队,RMQ) 洛谷 bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...
- [BZOJ4540][HNOI2016]序列 莫队
4540: [Hnoi2016]序列 Time Limit: 20 Sec Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...
- BZOJ 4540 [Hnoi2016]序列 (单调栈 + ST表 + 莫队算法)
题目链接 BZOJ4540 考虑莫队算法. 这题难在$[l, r]$到$[l, r+1]$的转移. 根据莫队算法的原理,这个时候答案应该加上 $cal(l, r+1) + cal(l+1, r+1) ...
- 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈
[BZOJ4540][Hnoi2016]序列 Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,a ...
- [bzoj4540][Hnoi2016][序列] (莫队算法+单调栈+st表)
Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar.若1≤l≤s≤t≤r≤n,则称a ...
- BZOJ.4542.[HNOI2016]大数(莫队)
题目链接 大数除法是很麻烦的,考虑能不能将其条件化简 一段区间[l,r]|p,即num[l,r]|p,类似前缀,记后缀suf[i]表示[i,n]的这段区间代表的数字 于是有 suf[l]-suf[r+ ...
随机推荐
- 【iOS开发-80】Quartz2D绘图简介:直线/圆形/椭圆/方形以及上下文栈管理CGContextSaveGState/CGContextRestoreGState
本文转载至 http://blog.csdn.net/weisubao/article/details/41282457 - (void)drawRect:(CGRect)rect { //获得当前上 ...
- MATLAB循环结构:for语句+定积分实例
for语句 格式: for 循环变量=表达式1:表达式2:表达式3 循环体语句 end 表达式1:循环变量初值:表达式2:步长:表达式3:循环变量终值. for 循环变量=矩阵表达式 循环体语句 en ...
- why factory pattern and when to use factory pattern
1 factory pattern本质上就是对对象创建进行抽象 抽象的好处是显然的,可以方便用户去获取对象. 2 使用factory pattern的时机 第一,当一个对象的创建依赖于其它很多对象的时 ...
- 【python】-- 文件操作
一.概述 我们工作中需要经常操作文件,下面就讲讲如何用Python操作文件 1.文件操作的流程: 打开文件,得到文件句柄赋值给一个变量 通过文件句柄,对文件进行操作 关闭文件 #获取文件句柄 f = ...
- 我的Android进阶之旅------>四种呼叫转移场景
运行商为我们提供了如下4中呼叫转移场景: 1.始终进行呼叫转移:不管当前手机处于何种状态,来电都会被转移到指定的电话号码上.在使用这种呼叫转移时应当非常小心,如果启用了这种呼叫转移,你可就永远也接不着 ...
- 18.Django原生SQL语句查询返回字典
在django中执行自定义语句的时候,返回的结果是一个tuple ,并我不是我所期望的dict.当结果是tuple 时,如果要取得数据,必须知道对应数据在结果集中的序号,用序号的方式去得到值. 如果是 ...
- ABAP内表数据做层次XML输出
*&---------------------------------------------------------------------**& Report Z_BARRY ...
- awk 字符串函数
awk 提供了许多强大的字符串函数,见下表: awk 内置字符串函数 gsub(r,s) 在整个 $0 中用 s 替代 r gsub(r,s,t) 在整个 t 中用 s 替代 r index(s,t) ...
- LeetCode:盛最多水的容器【11】
LeetCode:盛最多水的容器[11] 题目描述 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 ...
- mysql高可用研究(二) 主从+MHA+Atlas
关于Atlas的详细介绍请访问:https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md 为什么要使用Atlas?应用程序直连数据库不好吗? ...