codeforces515e(线段树)

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);
    }
}

代码还是略丑,虽然很快就想到了,但是改了好久。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值