51nod 1593 公园晨跑

有一只猴子,他生活在一个环形的公园里。有n棵树围绕着公园。第i棵树和第i+1棵树之间的距离是 di ,而第n棵树和第一棵树之间的距离是 dn 。第i棵树的高度是 hi 。

这只猴子每天要进行晨跑。晨跑的步骤如下:

· 他先选择两棵树;

· 然后爬上第一棵树;

· 再从第一棵树上下来,接着围绕着公园跑(有两个可能的方向)到第二棵树,然后爬上第二棵树;

· 最后从第二棵树上下来。

但是有一些小孩会在连续的一些树上玩耍。所以猴子不能经过这些树。

比如现在猴子选择的第x棵和第y棵树,那么该早晨他消耗的能量是 2(hx+hy)+dist(x,y) 。由于某一条路径是被小孩子占据的,所以他只能跑另外一条,因此 dist(x,y) 是确定的。

现在给出第i天,孩子们会在第 ai 棵树和 bi 棵树之间玩耍。具体的,如果 ai≤bi ,那么孩子玩耍的区间就是 [ai,bi] ,否则孩子玩耍的区间就是 [ai,n]⋃[1,bi] 。

请帮助这只猴子找出两棵树,让他晨跑的时候他能够消耗最大的能量。

Input

单组测试数据。

第一行有两个整数 n 和m (3≤n≤10^5, 1≤m≤10^5),表示树的数目,以及猴子跑步的天数。

第二行有n个整数d1,d2,...,dn (1≤di≤10^9),表示树之间的距离。

第三行有n个整数h1,h2,...,hn (1≤hi≤10^9),表示树的高度。

接下来m行,第一行有两个整数 ai和bi (1≤ai,bi≤n),描述每一天孩子玩耍的区间。输入保证至少有两个棵树孩子不会进行玩耍,这样猴子每天都可以晨跑了。

Output

对于每一天,输出猴子消耗的最大能量。

Input示例

样例输入1

5 3

2 2 2 2 2

3 5 2 1 4

1 3

2 2

4 5

Output示例

样例输出1

12

16

18

设d[i]为i点距离的前缀和,h[i]为原题中的2*h[i](因为要上一次树、下一次树),那么 i, j (i > j)两点间的价值可以表示为 d[i] - d[j] + h[i] + h[j], 设 A[i] = d[i] + h[i], B[j] = d[j] - h[j], 则价值就是 A[i] - B[j],在可选区间中选最大的A[i]减去最小的B[j]即可。

但需要考虑:如果使A[i]最大的i和使B[j]最小的j相同怎么办? 这时候,i和j中只能选择一个,然后分别在剩下的可用的位置中选择另一个即可。

具体实现我使用的是st表,线段树也可以……但是st表写起来短啊2333

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define INF 0x7fffffffffffffff
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
bool read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
else if(c == EOF) return 0;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
return 1;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 200005;
ll n, m, d[N], h[N], A[N], B[N];
ll mi[N][20], ma[N][20], lg[N];
ll MAX(int a, int b) { return A[a] > A[b] ? a : b; }
ll MIN(int a, int b) { return B[a] < B[b] ? a : b; }
void init(){
A[0] = -INF, B[0] = INF;
for(ll i = 1, sum = 0; i <= 2 * n; i++){
sum += d[i];
A[i] = sum + h[i];
B[i] = sum - h[i];
ma[i][0] = mi[i][0] = i;
}
for(ll i = 0, j = 1; j <= 2 * n; j++)
lg[j] = 1 << (i + 1) == j ? ++i : i;
for(int j = 1; (1 << j) <= 2 * n; j++)
for(int i = 1; i + (1 << j) - 1 <= 2 * n; i++){
ma[i][j] = MAX(ma[i][j - 1], ma[i + (1 << (j - 1))][j - 1]);
mi[i][j] = MIN(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
}
}
ll getma(int l, int r){
if(l > r) return 0;
int j = lg[r - l + 1];
return MAX(ma[l][j], ma[r - (1 << j) + 1][j]);
}
ll getmi(int l, int r){
if(l > r) return 0;
int j = lg[r - l + 1];
return MIN(mi[l][j], mi[r - (1 << j) + 1][j]);
}
ll query(int l, int r){
int x = getma(l, r), y = getmi(l, r);
if(x != y) return A[x] - B[y];
int another_x = MAX(getma(l, x - 1), getma(x + 1, r));
int another_y = MIN(getmi(l, x - 1), getma(x + 1, r));
return max(A[another_x] - B[y], A[x] - B[another_y]);
}
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++) read(d[i % n + 1]), d[i % n + 1 + n] = d[i % n + 1];
for(int i = 1; i <= n; i++) read(h[i]), h[i] <<= 1, h[i + n] = h[i];
init();
while(m--){
int a, b;
read(a), read(b);
if(a <= b) printf("%lld\n", query(b + 1, n + a - 1));
else printf("%lld\n", query(b + 1, a - 1));
}
return 0;
}

51nod 1593 公园晨跑 | ST表(线段树?)思维题的更多相关文章

  1. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  2. (DP ST表 线段树)51NOD 1174 区间中最大的数

    给出一个有N个数的序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,最大的数是多少.   例如: 1 7 6 3 1.i = 1, j = 3,对应的数为7 6 3,最大的数为7. ...

  3. Glad You Came hdu-6356(ST表 || 线段树)

    第一种用线段树,用两颗数维护区间最大值和区间的最小值,然后更新的时候如果我目前区间内的最大值比我得到的v小,那么我就把这个区间修改成v,如果我的最小值比v大,那么v就是没有用的,直接跳过,然后这样每次 ...

  4. Codeforces 487B Strip (ST表+线段树维护DP 或 单调队列优化DP)

    题目链接 Strip 题意   把一个数列分成连续的$k$段,要求满足每一段内的元素最大值和最小值的差值不超过$s$, 同时每一段内的元素个数要大于等于$l$, 求$k$的最小值. 考虑$DP$ 设$ ...

  5. bzoj 1699: [Usaco2007 Jan]Balanced Lineup排队【st表||线段树】

    要求区间取min和max,可以用st表或线段树维护 st表 #include<iostream> #include<cstdio> using namespace std; c ...

  6. [luoguP1816] 忠诚(st表 || 线段树)

    传送门 其实我就是想练练 st表 本以为学了线段树可以省点事不学 st表 了 但是后缀数组中用 st表 貌似很方便 所以还是学了吧,反正也不难 ——代码 #include <cstdio> ...

  7. RMQ--树状数组,ST表,线段树

    RMQ Range Minimum/Maximum Query 区间最值问题 树状数组 https://www.cnblogs.com/xenny/p/9739600.html lowbit(x) x ...

  8. st表、树状数组与线段树 笔记与思路整理

    已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...

  9. Hdu5737-Differencia(有序表线段树)

    题意很直观,我就不说了. 解析:这是我以前没有接触过的线段树类型,有序表线段树,每个节点申请了两段空间,主要是为了保存左边儿子会有多少比v小的,右边儿子会有多少比v小 的,所以在建树过程中要归并排序. ...

随机推荐

  1. Mac系统实现git命令自动补全

    当我第一次使用mac电脑的时候,由于我是从事软件开发的程序员,所以必须经常要使用到git,然而发现在mac系统下,git不能实现命令的自动补全,然后网上查找资料,找到了解决办法,终于可以实现了git命 ...

  2. 201521123092《java程序设计》第六周学习总结

    1.本周学习总结 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2.书面作业 1.clone方法 1.1 Object对象中的clo ...

  3. 201521123039《Java程序设计》 第二周学习总结

    1.本周学习总结 答:上课老师介绍了Java基本的数据类型,需要注意的地方有:**java的整型数都为带符号数**,**byte类型范围(-127,128)太小,所以我们一般不使用byte型,byte ...

  4. Java SVN管理工具的使用

    1.svn环境搭建 在应用myEclips 8.5做项目时,svn会成为团队项目的一个非常好的工具,苦苦在网上寻求了一下午,终于整合好了这个环境,在这里简单介绍下,希望能为刚开始用svn的朋友一点点帮 ...

  5. 【java】聊聊java里的接口

    接口的概念 java中的接口用于描述类应该具备什么样的功能,而不给出具体的实现,一个类可以“实现”多个接口 [注意]接口不是类,而是对类的一组描述   还是让我们通过一个例子来看看接口如何运作吧!   ...

  6. pyhton之路---面向对象

    一.面向过程VS面向对象 面向过程:      优点:极大的降低了写程序的复杂度,只需要顺着执行的步骤,堆叠代码即可.      缺点:一套流水线或者流程就是来解决一个问题,代码就是牵一发而动全身 面 ...

  7. AJAX多级下拉联动【JSON】

    前言 前面我们已经使用过了XML作为数据载体在AJAX中与服务器进行交互.当时候我们的案例是二级联动,使用Servlet进行控制 这次我们使用JSON作为数据载体在AJAX与服务器交互,使用三级联动, ...

  8. Spring第五篇【cglib、手动实现AOP编程】

    前言 到目前为止,已经简单学习了Spring的Core模块.也会怎么与Struts2框架进行整合了-.于是我们就开启了Spring的AOP模块了-在讲解AOP模块之前,首先我们来讲解一下cglib代理 ...

  9. Struts2第六篇【文件上传和下载】

    前言 在讲解开山篇的时候就已经说了,Struts2框架封装了文件上传的功能--..本博文主要讲解怎么使用Struts框架来完成文件上传和下载 回顾以前的文件上传 首先,我们先来回顾一下以前,我们在we ...

  10. 03标准对象-02-RegExp 正则表达式

    1.基本概念 和 定义 用一种描述性的语言来给字符串定义一个规则,你可以形象地理解正则表达式是一个"框",凡是符合大小形状条件的字符串,都算是"匹配"了. JS ...