E. Drazil and Park
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Drazil is a monkey. He lives in a circular park. There are n trees around the park. The distance between the i-th tree and (i + 1)-st trees is di, the distance between the n-th tree and the first tree is dn. The height of the i-th tree is hi.
Drazil starts each day with the morning run. The morning run consists of the following steps:
- Drazil chooses two different trees
- He starts with climbing up the first tree
- Then he climbs down the first tree, runs around the park (in one of two possible directions) to the second tree, and climbs on it
- Then he finally climbs down the second tree.
But there are always children playing around some consecutive trees. Drazil can't stand children, so he can't choose the trees close to children. He even can't stay close to those trees.
If the two trees Drazil chooses are x-th and y-th, we can estimate the energy the morning run takes to him as 2(hx + hy) + dist(x, y). Since there are children on exactly one of two arcs connecting x and y, the distance dist(x, y) between trees x and y is uniquely defined.
Now, you know that on the i-th day children play between ai-th tree and bi-th tree. More formally, if ai ≤ bi, children play around the trees with indices from range [ai, bi], otherwise they play around the trees with indices from .
Please help Drazil to determine which two trees he should choose in order to consume the most energy (since he wants to become fit and cool-looking monkey) and report the resulting amount of energy for each day.
Input
The first line contains two integer n and m (3 ≤ n ≤ 105, 1 ≤ m ≤ 105), denoting number of trees and number of days, respectively.
The second line contains n integers d1, d2, ..., dn (1 ≤ di ≤ 109), the distances between consecutive trees.
The third line contains n integers h1, h2, ..., hn (1 ≤ hi ≤ 109), the heights of trees.
Each of following m lines contains two integers ai and bi (1 ≤ ai, bi ≤ n) describing each new day. There are always at least two different trees Drazil can choose that are not affected by children.
Output
For each day print the answer in a separate line.
Examples
input
Copy
5 3 2 2 2 2 2 3 5 2 1 4 1 3 2 2 4 5
output
Copy
12 16 18
input
Copy
3 3 5 1 4 5 1 4 3 3 2 2 1 1
output
Copy
17 22 11
题意:给出一个数组形成的环,换上每个元素都有点权值hi,环中每两个相邻元素之间有距离di,环上两点之间的权值大小等于两点点权值*2的和加上两点之间的距离(有两种走法),现在有a~b这一段不准通行,求得剩下可以通行的点中最大的两点之间的权值。
思路:采用线段树(复制一个环,将第二个环的首端接到第一个环的尾端,这样再查询的时候就可以由完整一段),每个节点不仅要记录这一段的最大值max,还要记录线段左端点连接的最大值maxl,和线段右端点连接的最大值maxr,建线段树的时候自底向上更新权值(父亲的max有可能等于左儿子的maxr+右儿子的maxl+中间空隙距离),在查询的时候也要记录每一小段的max、maxl、maxr。这样才能保证找到最大值。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define L(x) (x << 1)//左儿子
#define R(x) (x << 1 | 1)//右儿子
#define sz(x) (tree[x].r - tree[x].l + 1)//区间大小
using namespace std;
typedef long long ll;
const int maxn = 2e5+100;
ll n,m;
ll d[maxn],h[maxn];
ll pred[maxn];
// l == 左;r == 右;p == now;
struct tree{
int l,r;
ll max;//最值标记
ll maxl,maxr;
}tree[maxn << 2];
//简单的建立
void build(ll l,ll r,ll p){
tree[p].l = l,tree[p].r = r;
if(l == r){
tree[p].max = h[l]*2;
tree[p].maxl = h[l]*2;
tree[p].maxr = h[r]*2;
return;
}
ll mid = (tree[p].l + tree[p].r) >> 1;
build(l,mid,L(p)); build(mid + 1,r,R(p));
if(l==mid&&mid+1==r)
{
tree[p].max = h[l] * 2 + h[r] * 2 + d[l];
tree[p].maxl = max(h[r]*2 + d[l],h[l]*2);
tree[p].maxr = max(h[l]*2 + d[l] , h[r]*2);
}
else if(l==mid)
{
tree[p].max = max(tree[R(p)].max,tree[R(p)].maxl + d[l] + h[l]*2);
tree[p].maxl = max(h[l]*2,tree[R(p)].maxl + d[l]);
ll rightwhole = pred[r-1] - pred[mid-1];
tree[p].maxr = max(tree[R(p)].maxr,rightwhole + h[l]*2);
}
else if(mid+1==r)
{
tree[p].max = max(tree[L(p)].max,tree[L(p)].maxr + d[mid] + h[r]*2);
ll leftwhole = pred[mid] - pred[l-1];
tree[p].maxl = max(tree[L(p)].maxl,leftwhole + h[r]*2);
tree[p].maxr = max(h[r]*2,tree[L(p)].maxr + d[mid]);
}
else
{
tree[p].max = max(tree[L(p)].max,tree[R(p)].max);
tree[p].max = max(tree[p].max,tree[L(p)].maxr + tree[R(p)].maxl + d[mid]);
ll leftwhole = pred[mid] - pred[l-1];
tree[p].maxl = max(tree[L(p)].maxl,leftwhole + tree[R(p)].maxl);
ll rightwhole = pred[r-1] - pred[mid-1];
tree[p].maxr = max(tree[R(p)].maxr,rightwhole + tree[L(p)].maxr);
}
}
//区间最大值
ll ask_max(int l,int r,int p,ll&maxl,ll&maxr){
if(l <= tree[p].l && tree[p].r <= r)
{
maxl = tree[p].maxl;
maxr = tree[p].maxr;
return tree[p].max;
}
if(l>tree[p].r||r<tree[p].l)return 0;
ll ans = 0;
ll l_l=0,l_r=0,r_l=0,r_r=0;
int mid = (tree[p].l + tree[p].r) >> 1;
ll lmax=-1,rmax=-1;
if(l <= mid)
{
lmax = ask_max(l,r,L(p),l_l,l_r);
ans = max(ans,lmax);
}
if(mid < r)
{
rmax = ask_max(l,r,R(p),r_l,r_r);
ans = max(ans,rmax);
}
if(l <= mid&&mid < r)
{
ans = max(ans,l_r + r_l + d[mid]);
ll leftwhole = pred[mid] - pred[max(l-1,tree[p].l-1)];
maxl = max(l_l,leftwhole + r_l);
ll rightwhole = pred[min(r-1,tree[p].r-1)] - pred[mid-1];
maxr = max(r_r,rightwhole + l_r);
}
else if(l<=mid)
maxl = l_l,maxr = -1;
else if(r>mid)
maxr = r_r,maxl = -1;
else
maxl = maxr = -1;
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;i++)
{
scanf("%I64d",&d[i]);
d[n+i] = d[i];
}
for(int i = 1;i<=2*n;i++)pred[i] = pred[i-1] + d[i];
for(int i = 1;i<=n;i++)
{
scanf("%I64d",&h[i]);
h[n+i] = h[i];
}
int tmp = n;
n *= 2;
build(1,n,1);
int a,b;
ll ans;
ll maxl,maxr;
while(m--)
{
scanf("%d%d",&a,&b);
if(a<=b)
ans = ask_max(b+1,a+tmp-1,1,maxl,maxr);
else
ans = ask_max(b+1,a-1,1,maxl,maxr);
printf("%I64d\n",ans);
}
}
代码还是略丑,虽然很快就想到了,但是改了好久。