Description

题库链接

给你一个长度为 \(n\) 的序列 \(A\) ,给出 \(q\) 组询问。每次询问 \([l,r]\) ,求该区间内所有的子序列中最小值的和。

\(1\leq n,q\leq 100000,|A_i|\leq 10^9\)

Solution

考虑把右端点右移时,会产生 \(r-l+1\) 个新的区间,我们可以来统计这 \(r-l+1\) 个区间的最小值和。

记 \(pre_i\) 为从第 \(i\) 位往左走第一个值比 \(A_i\) 小的位置。

显然在 \(l'\in(pre_r,r]\) 的区间 \([l',r]\) 中的最小值为 \(A_r\) 。

我们可以用这个性质做一遍前缀。记 \(sum_i\) 为右端点为 \(i\) 时,左端点在 \([1,i]\) 这段区间内所有区间中最小值的和。很容易用单调栈预处理出来。

那么对于移动右端点时,我们记 \(loc\) 为这段区间内的最小值所在的位置,显然移动右端点产生的贡献为 \(sum_r-sum_{loc}+A_{loc}\cdot(loc-l+1)\) 。

查询最小值可以用 \(st\) 表来解决。

对于移动左端点也类似,从右往左处理就好了。其余的就用莫队来实现。

Code

//It is made by Awson on 2018.2.12
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 100000;
void read(int &x) {
char ch; bool flag = 0;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
x *= 1-2*flag;
}
void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); } #define log2 LOG
int n, q, lim, block, a[N+5], log2[N+5], pre[N+5], nex[N+5], f[N+5][20], bin[25];
LL suml[N+5], sumr[N+5], ans[N+5];
int s[N+5], top;
struct tt {
int l, r, id;
bool operator < (const tt &b) const {return l/block == b.l/block ? r < b.r : l < b.l; }
}qry[N+5]; int query(int l, int r) {int lim = log2[r-l+1]; return a[f[l][lim]] < a[f[r-bin[lim]+1][lim]] ? f[l][lim] : f[r-bin[lim]+1][lim]; }
LL movel(int l, int r) {int loc = query(l, r); return sumr[l]-sumr[loc]+1ll*a[loc]*(r-loc+1); }
LL mover(int l, int r) {int loc = query(l, r); return suml[r]-suml[loc]+1ll*a[loc]*(loc-l+1); }
void work() {
read(n), read(q); for (int i = 1; i <= n; i++) read(a[i]), f[i][0] = i;
log2[0] = -1; for (int i = 1; i <= n; i++) log2[i] = log2[i>>1]+1;
bin[0] = 1; for (int i = 1; i <= 20; i++) bin[i] = bin[i-1]<<1;
lim = log2[n], block = sqrt(n);
for (int i = 1; i <= n; i++) {
while (top != 0 && a[s[top]] >= a[i]) --top;
pre[i] = top == 0 ? 0 : s[top]; s[++top] = i;
}
s[top = 0] = 0;
for (int i = n; i >= 1; i--) {
while (top != 0 && a[s[top]] >= a[i]) --top;
nex[i] = top == 0 ? n+1 : s[top]; s[++top] = i;
}
for (int i = 1; i <= n; i++) suml[i] = suml[pre[i]]+1ll*(i-pre[i])*a[i];
for (int i = n; i >= 1; i--) sumr[i] = sumr[nex[i]]+1ll*(nex[i]-i)*a[i];
for (int i = 1; i <= lim; i++) for (int j = 1; j <= n; j++) {
if (j+bin[i-1] > n) break;
f[j][i] = a[f[j][i-1]] < a[f[j+bin[i-1]][i-1]] ? f[j][i-1] : f[j+bin[i-1]][i-1];
}
for (int i = 1; i <= q; i++) read(qry[i].l), read(qry[i].r), qry[i].id = i;
sort(qry+1, qry+1+q);
int curl = 1, curr = 0; LL now = 0;
for (int i = 1; i <= q; i++) {
int l = qry[i].l, r = qry[i].r;
while (curr < r) ++curr, now += mover(curl, curr);
while (curl > l) --curl, now += movel(curl, curr);
while (curr > r) now -= mover(curl, curr), --curr;
while (curl < l) now -= movel(curl, curr), ++curl;
ans[qry[i].id] = now;
}
for (int i = 1; i <= q; i++) writeln(ans[i]);
}
int main() {
work(); return 0;
}

[HNOI 2016]序列的更多相关文章

  1. bzoj 4540 [HNOI 2016] 序列 - 莫队算法 - Sparse-Table - 单调栈

    题目传送门 传送点I 传送点II 题目大意 给定一个长度为$n$的序列.询问区间$[l, r]$的所有不同的子序列的最小值的和. 这里的子序列是连续的.两个子序列不同当且仅当它们的左端点或右端点不同. ...

  2. [HNOI 2016]树

    Description 题库链接 给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) :我们称这颗树为模板树.需要通过这棵模板树来构建一颗大树.构建过程如 ...

  3. 【HNOI 2016】序列

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

  4. 「HNOI 2016」 序列

    \(Description\) 给你一个序列,每次询问一个区间,求其所有子区间的最小值之和 \(Solution\) 这里要用莫队算法 首先令\(val\)数组为原序列 我们考虑怎么由一个区间\([l ...

  5. hnoi 2016 省选总结

    感觉省选好难的说...反正我数据结构太垃圾正解想到了也打不出来打一打暴力就滚粗了! DAY1 0+20+30 DAY2 60-20+0+60 最后170-20分,暴力分还是没有拿全! 然而这次是给了5 ...

  6. HNOI 2016 省队集训日记

    第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里.  ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...

  7. 【HNOI 2016】网络

    Problem Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器 ...

  8. [BZOJ 4537][Hnoi 2016]最小公倍数

    传送门 并查集+分块 看到题目可以想到暴力做法, 对于每个询问, 将所有a和b小于等于询问值的的边加入图中(用并查集), 如果询问的u和v在一个联通块中, 且该联通块的maxa和maxb均等与询问的a ...

  9. 【BZOJ 4539】【HNOI 2016】树

    http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n ...

随机推荐

  1. Transaction 事务简单详解

    Transaction 也就是所谓的事务了,通俗理解就是一件事情.从小,父母就教育我们,做事情要有始有终,不能半途而废. 事务也是这样,不能做一半就不做了,要么做完,要么就不做.也就是说,事务必须是一 ...

  2. js计时功能

    //个位秒加 function time4jia() { //分钟60为上限 所有加停止 if (sz(a('time1').innerHTML) == 6) { return; } var m4 = ...

  3. C语言--第0周作业

    1.翻阅邹欣老师博客关于师生关系博客,并回答下列问题: 1)最理想的师生关系是健身教练和学员的关系,在这种师生关系中你期望获得来自老师的哪些帮助? 答: 若教练和学员的关系是最理想的师生关系,那就意味 ...

  4. oracle删除某个用户所有表(转)

    1. select   'Drop   table   '||table_name||';'             from   all_tables           where   owner ...

  5. Django 测试驱动开发

    第一章 1.编写functional_tests.py from selenium import webdriver browser = webdriver.Firefox() browser.get ...

  6. 《高级软件测试》Windows平台Jira的配置

    昨天完成了Jira的下载,很开心地去睡觉等明天天亮秒配环境愉快进行使用,撰写文档,开始徜徉于软件管理测试实践,早日走向代码巅峰. 我们把安装和配置的过程来走一遍. 安装完成汤姆猫长这样子: 安装Jir ...

  7. poj2029 Get Many Persimmon Trees

    http://poj.org/problem?id=2029 单点修改 矩阵查询 二维线段树 #include<cstdio> #include<cstring> #inclu ...

  8. java的<<左移,>>右移,>>>无符号右移

    >>右移 右移,道在二进制中,假设用一个32位的Int表示一个64,那么高位就都是0,所以当我们把整个二进制数右移,如0100000 >> 2 = 0001000,可以看到右移 ...

  9. EasyUI datagrid 使用小结

    用了 EasyUI 框架一段时间了,这个前端框架用起来还是挺方便的,也有很多现成的控件,看看官方文档应该还是能比较快用起来的. 在这里记录一下一些常用的控件的方法,遇到过的bug或者当初耗了一点时间来 ...

  10. SpringBoot14 SpringBoot整合mybatis

    1 版本说明 springboot:2.0 jdk:1.8 2 创建springBoot项目 创建项目时勾选必要web,MySQL,mybatis相关依赖 创建完成后再pom文件中添加自动部署.lom ...