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. Leetcode 4——Partition List

    Problems: Given a linked list and a value x, partition it such that all nodes less than x come befor ...

  2. C语言第二次博客作业

    一.PTA实验作业 题目1:计算分段函数[2] 本题目要求计算下列分段函数f(x)的值: 1.实验代码 int main (void) { double x,y; scanf("%lf&qu ...

  3. python实现K聚类算法

    参考:<机器学习实战>- Machine Learning in Action 一. 基本思想  聚类是一种无监督的学习,它将相似的对象归到同一簇中.它有点像全自动分类.聚类方法几乎可以应 ...

  4. Alpha冲刺Day6

    Alpha冲刺Day6 一:站立式会议 今日安排: 由张梨贤继续完成前一天委托第三方剩余的内容,并完成委托情况查看这一子模块 由黄腾飞继续完成前一天企业自查风险管理剩余的内容,并完成风险上报这一子模块 ...

  5. 《招一个靠谱的移动开发》iOS面试题及详解(上篇)

    以下问题主要用于技术的总结与回顾 主要问题总结 单例的写法.在单利中创建数组应该注意些什么. NSString 的时候用copy和strong的区别. 多线程.特别是NSOperation 和 GCD ...

  6. border 三角形 有边框的 东西南北的 气泡三角形

    链接地址:http://www.cnblogs.com/blosaa/p/3823695.html

  7. .Net Core MongoDB 简单操作。

    一:MongoDB 简单操作类.这里引用了MongoDB.Driver. using MongoDB.Bson; using MongoDB.Driver; using System; using S ...

  8. PHP分页初探 一个最简单的PHP分页代码的简单实现

    PHP分页代码在各种程序开发中都是必须要用到的,在网站开发中更是必选的一项. 要想写出分页代码,首先你要理解SQL查询语句:select * from goods limit 2,7.PHP分页代码核 ...

  9. js数组string对象api常用方法

    charAt() 方法可返回指定位置的字符. stringObject.charAt(index) indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. stringObject ...

  10. Linux搭建Apache+Tomcat实现负载均衡

    一.首先需要安装java,详见http://www.cnblogs.com/fun0623/p/4350004.html 二.编译安装Apache,详见http://www.cnblogs.com/f ...