[HNOI 2016]序列
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]序列的更多相关文章
- bzoj 4540 [HNOI 2016] 序列 - 莫队算法 - Sparse-Table - 单调栈
题目传送门 传送点I 传送点II 题目大意 给定一个长度为$n$的序列.询问区间$[l, r]$的所有不同的子序列的最小值的和. 这里的子序列是连续的.两个子序列不同当且仅当它们的左端点或右端点不同. ...
- [HNOI 2016]树
Description 题库链接 给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) :我们称这颗树为模板树.需要通过这棵模板树来构建一颗大树.构建过程如 ...
- 【HNOI 2016】序列
Problem Description 给定长度为 \(n\) 的序列:\(a_1, a_2, \cdots , a_n\),记为 \(a[1 \colon n]\).类似地,\(a[l \colon ...
- 「HNOI 2016」 序列
\(Description\) 给你一个序列,每次询问一个区间,求其所有子区间的最小值之和 \(Solution\) 这里要用莫队算法 首先令\(val\)数组为原序列 我们考虑怎么由一个区间\([l ...
- hnoi 2016 省选总结
感觉省选好难的说...反正我数据结构太垃圾正解想到了也打不出来打一打暴力就滚粗了! DAY1 0+20+30 DAY2 60-20+0+60 最后170-20分,暴力分还是没有拿全! 然而这次是给了5 ...
- HNOI 2016 省队集训日记
第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里. ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...
- 【HNOI 2016】网络
Problem Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器 ...
- [BZOJ 4537][Hnoi 2016]最小公倍数
传送门 并查集+分块 看到题目可以想到暴力做法, 对于每个询问, 将所有a和b小于等于询问值的的边加入图中(用并查集), 如果询问的u和v在一个联通块中, 且该联通块的maxa和maxb均等与询问的a ...
- 【BZOJ 4539】【HNOI 2016】树
http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n ...
随机推荐
- 掌握这些回答技术面试题的诀窍,让你offer拿到手软。
三.四月份,春回大地,万物复苏(请自带赵忠祥老师的BGM),又到了不少同学的跳槽时节. 最近一段时间团队也在招人,这期间筛选了不少简历,面试了一些候选人.这里谈谈我自己的对「怎样回答面试题」的理解. ...
- 赛博杯-HMI流水灯-stack
stack(ret2libc) 分析 首先checksec一下,发现没开栈保护,可能是栈溢出. [*] '/root/Desktop/bin/pwn/stack_/stack' Arch: i386- ...
- alpha-咸鱼冲刺day1
一,合照 emmmmm.自然是没有的. 二,项目燃尽图 三,项目进展 登陆界面随意写了一下.(明天用来做测试的) 把学姐给我的模板改成了自家的个人主页界面,侧边栏啥的都弄出来了(快撒花花!) 四,问题 ...
- 个人作业2——NBA 2k18案例分析
产品:篮球体育类游戏NBA 2k18 选择理由:这款游戏是<NBA 2k>的正统续作,自己和身边的朋友都对篮球比较感兴趣,经常看NBA,所以近几年的版本都有购买下载,加上游戏中人物动作比较 ...
- C语言——第四次作业
题目 题目一:计算分段函数 1.实验代码 #include <stdio.h> int main() { double x,y; scanf("%lf",&x) ...
- xapp1151_Param_CAM模块安装
xapp1151_Param_CAM模块安装 所需生成模块 TCAM CAM 下载链接 赛灵思技术支持网站:http://www.xilinx.com/support.html 并在网页中搜索xapp ...
- 《javascript设计模式与开发实践》阅读笔记(13)—— 职责链模式
职责链模式 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 书里的订单的例子 假设我们负责一个售卖手机 ...
- Web移动端适配总结
移动端适配的相关概念以及几种方案总结 适配相关概念 布局视口(layout viewport):html元素的上一级容器即顶级容器,用于解决页面在手机上显示的问题.大部分移动设备都将这个视口分辨率设置 ...
- 图数据库orientDB(1-2)例子
http://gog.orientdb.com/index.html#/infotab 小朱25岁,出生在教师家庭并且有个姐姐小田,他现在奋斗在帝都. 那么SQL是这样滴!!! CREATE VER ...
- GIT入门笔记(19)GIT 小结
1.add和commit为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:$ git add file1.txt$ g ...