Drazil and Park (Codeforces 515E)
Tags: Others, data structures

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.


Sample Inputs:
5 3
2 2 2 2 2
3 5 2 1 4
1 3
2 2
4 5

3 3
5 1 4
5 1 4
3 3
2 2
1 1

Sample Outputs:
12
16
18

17
22
11

Solution (Python):
import sys
readline = sys.stdin.readline

class Segment_Tree:

    def __init__(self, N, f, e, lst=None):
        self.f = f
        self.e = e
        self.N = N
        if lst == None:
            self.segment_tree = [self.e] * 2 * self.N
        else:
            assert len(lst) <= self.N
            self.segment_tree = [self.e] * self.N + [x for x in lst] + [self.e] * (N - len(lst))
            for i in range(self.N - 1, 0, -1):
                self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def __getitem__(self, i):
        if type(i) == int:
            if -self.N <= i < 0:
                return self.segment_tree[i + self.N * 2]
            elif 0 <= i < self.N:
                return self.segment_tree[i + self.N]
            else:
                raise IndexError('list index out of range')
        else:
            (a, b, c) = (i.start, i.stop, i.step)
            if a == None:
                a = self.N
            else:
                a += self.N
            if b == None:
                b = self.N * 2
            else:
                b += self.N
            return self.segment_tree[slice(a, b, c)]

    def __setitem__(self, i, x):
        if -self.N <= i < 0:
            i += self.N * 2
        elif 0 <= i < self.N:
            i += self.N
        else:
            raise IndexError('list index out of range')
        self.segment_tree[i] = x
        while i > 1:
            i >>= 1
            self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def Build(self, lst):
        for (i, x) in enumerate(lst, self.N):
            self.segment_tree[i] = x
        for i in range(self.N - 1, 0, -1):
            self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def Fold(self, L=None, R=None):
        L += self.N
        R += self.N
        vL = self.e
        vR = self.e
        while L < R:
            if L & 1:
                vL = self.f(vL, self.segment_tree[L])
                L += 1
            if R & 1:
                R -= 1
                vR = self.f(self.segment_tree[R], vR)
            L >>= 1
            R >>= 1
        return self.f(vL, vR)

    def Fold_Index(self, L=None, R=None):
        if L == None:
            L = self.N
        else:
            L += self.N
        if R == None:
            R = self.N * 2
        else:
            R += self.N
        if L == R:
            return None
        x = self.Fold(L - self.N, R - self.N)
        while L < R:
            if L & 1:
                if self.segment_tree[L] == x:
                    i = L
                    break
                L += 1
            if R & 1:
                R -= 1
                if self.segment_tree[R] == x:
                    i = R
                    break
            L >>= 1
            R >>= 1
        while i < self.N:
            if self.segment_tree[i] == self.segment_tree[i << 1]:
                i <<= 1
            else:
                i <<= 1
                i |= 1
        i -= self.N
        return i

    def Bisect_Right(self, l=None, f=None):
        if l == self.N:
            return self.N
        if l == None:
            l = 0
        if f(self.Fold(l, self.N)):
            return self.N
        l += self.N
        v = self.e
        while True:
            while l % 2 == 0:
                l >>= 1
            vv = self.f(v, self.segment_tree[l])
            if f(vv):
                v = vv
                l += 1
                if 2 * self.N == l << self.N.bit_length() - l.bit_length() + 1:
                    return self.N
            else:
                while l < self.N:
                    l <<= 1
                    vv = self.f(v, self.segment_tree[l])
                    if f(vv):
                        v = vv
                        l += 1
                return l - self.N

    def Bisect_Left(self, r=None, f=None):
        if r == 0:
            return 0
        if r == None:
            r = self.N
        if f(self.Fold(0, r)):
            return 0
        r += self.N
        v = self.e
        while True:
            r -= 1
            while r > 1 and r % 2:
                r >>= 1
            vv = self.f(self.segment_tree[r], v)
            if f(vv):
                v = vv
                if 2 * self.N == r << self.N.bit_length() - r.bit_length() + 1:
                    return 0
            else:
                while r < self.N:
                    r = 2 * r + 1
                    vv = self.f(self.segment_tree[r], v)
                    if f(vv):
                        v = vv
                        r -= 1
                return r + 1 - self.N

    def __str__(self):
        return '[' + ', '.join(map(str, self.segment_tree[self.N:])) + ']'
(N, M) = map(int, readline().split())
D = list(map(int, readline().split()))
H = list(map(int, readline().split()))
STL = [0] * N
STR = [0] * N
for i in range(1, N):
    STL[i] = STL[i - 1] + D[i - 1]
for i in range(N - 2, -1, -1):
    STR[i] += STR[i + 1] + D[i]
for i in range(N):
    STL[i] += H[i] * 2
    STR[i] += H[i] * 2
ST0 = [0] * N
ST1 = [0] * N
for i in range(1, N):
    ST0[i] = ST0[i - 1] - D[i - 1]
    ST1[i] = ST1[i - 1] + D[i - 1]
for i in range(N):
    ST0[i] += H[i] * 2
    ST1[i] += H[i] * 2
inf = 1 << 60
STL = Segment_Tree(N, max, -inf, STL)
STR = Segment_Tree(N, max, -inf, STR)
ST0 = Segment_Tree(N, max, -inf, ST0)
ST1 = Segment_Tree(N, max, -inf, ST1)
d = D[N - 1]
for i in range(M):
    (a, b) = map(int, readline().split())
    ans = -inf
    a -= 1
    if a <= b:
        ans = max(ans, STL.Fold(0, a) + STR.Fold(b, N) + d)
        if 2 <= a:
            x = ST1.Fold_Index(0, a)
            ans = max(ans, ST0.Fold(0, x) + ST1[x])
            ans = max(ans, ST0[x] + ST1.Fold(x + 1, a))
        if b + 2 <= N:
            x = ST1.Fold_Index(b, N)
            ans = max(ans, ST0.Fold(b, x) + ST1[x])
            ans = max(ans, ST0[x] + ST1.Fold(x + 1, N))
    else:
        x = ST1.Fold_Index(b, a)
        ans = max(ans, ST0.Fold(b, x) + ST1[x])
        ans = max(ans, ST0[x] + ST1.Fold(x + 1, a))
    print(ans)

Solution (Python):
from math import inf
import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')
fast_print = lambda p: sys.stdout.write(str(p) + '\n')
(n, m) = [int(component) for component in input().split(' ')]
d = [int(component) for component in input().split(' ')]
h = [int(component) for component in input().split(' ')]

def get_prefix_sums(arr):
    prefix = [0] * (len(arr) + 1)
    for index in range(1, len(arr) + 1):
        prefix[index] = prefix[index - 1] + arr[index - 1]
    return prefix
prefix = get_prefix_sums(d)

def get_dist(l, r):
    return prefix[r] - prefix[l]

def merge(s1, s2):
    if s1 == None:
        return s2
    if s2 == None:
        return s1
    (llbm, lrbm, lism, ll, lr) = s1
    (rlbm, rrbm, rism, rl, rr) = s2
    nlbm = max(llbm, get_dist(ll, rl) + rlbm)
    nrbm = max(lrbm + get_dist(lr, rr), rrbm)
    nism = max(lism, lrbm + get_dist(lr, rl) + rlbm, rism)
    return (nlbm, nrbm, nism, ll, rr)

def make_segment_tree(d, h):
    N = len(d)
    size = 1 << (N - 1).bit_length()
    tree = [None] * (2 * size)
    for k in range(N):
        tree[size + k] = (2 * h[k], 2 * h[k], -inf, k, k)
    for k in range(size - 1, 0, -1):
        tree[k] = merge(tree[2 * k], tree[2 * k + 1])
    return tree

def range_query(tree, l, r):
    lres = None
    rres = None
    l += len(tree) >> 1
    r += (len(tree) >> 1) + 1
    while l < r:
        if l & 1:
            lres = merge(lres, tree[l])
            l += 1
        if r & 1:
            r -= 1
            rres = merge(tree[r], rres)
        l >>= 1
        r >>= 1
    res = merge(lres, rres)
    return res
tree = make_segment_tree(d, h)

def complex_query(l, r):
    if l <= r:
        if l > 0 and r < n - 1:
            (llbm, _, lism, _, _) = range_query(tree, 0, l - 1)
            (_, rrbm, rism, _, _) = range_query(tree, r + 1, n - 1)
            return max(lism, rism, llbm + d[-1] + rrbm)
        elif l == 0:
            (_, _, ism, _, _) = range_query(tree, r + 1, n - 1)
            return ism
        else:
            (_, _, ism, _, _) = range_query(tree, 0, l - 1)
            return ism
    else:
        (_, _, ism, _, _) = range_query(tree, r + 1, l - 1)
        return ism
for _ in range(m):
    (a, b) = [int(component) for component in input().split(' ')]
    fast_print(complex_query(a - 1, b - 1))

Solution (Python):
import sys
readline = sys.stdin.readline

class Segment_Tree:

    def __init__(self, N, f, e, lst=None):
        self.f = f
        self.e = e
        self.N = N
        if lst == None:
            self.segment_tree = [self.e] * 2 * self.N
        else:
            assert len(lst) <= self.N
            self.segment_tree = [self.e] * self.N + [x for x in lst] + [self.e] * (N - len(lst))
            for i in range(self.N - 1, 0, -1):
                self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def __getitem__(self, i):
        if type(i) == int:
            if -self.N <= i < 0:
                return self.segment_tree[i + self.N * 2]
            elif 0 <= i < self.N:
                return self.segment_tree[i + self.N]
            else:
                raise IndexError('list index out of range')
        else:
            (a, b, c) = (i.start, i.stop, i.step)
            if a == None:
                a = self.N
            else:
                a += self.N
            if b == None:
                b = self.N * 2
            else:
                b += self.N
            return self.segment_tree[slice(a, b, c)]

    def __setitem__(self, i, x):
        if -self.N <= i < 0:
            i += self.N * 2
        elif 0 <= i < self.N:
            i += self.N
        else:
            raise IndexError('list index out of range')
        self.segment_tree[i] = x
        while i > 1:
            i >>= 1
            self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def Build(self, lst):
        for (i, x) in enumerate(lst, self.N):
            self.segment_tree[i] = x
        for i in range(self.N - 1, 0, -1):
            self.segment_tree[i] = self.f(self.segment_tree[i << 1], self.segment_tree[i << 1 | 1])

    def Fold(self, L=None, R=None):
        L += self.N
        R += self.N
        vL = self.e
        vR = self.e
        while L < R:
            if L & 1:
                vL = self.f(vL, self.segment_tree[L])
                L += 1
            if R & 1:
                R -= 1
                vR = self.f(self.segment_tree[R], vR)
            L >>= 1
            R >>= 1
        return self.f(vL, vR)

    def Fold_Index(self, L=None, R=None):
        if L == None:
            L = self.N
        else:
            L += self.N
        if R == None:
            R = self.N * 2
        else:
            R += self.N
        if L == R:
            return None
        x = self.Fold(L - self.N, R - self.N)
        while L < R:
            if L & 1:
                if self.segment_tree[L] == x:
                    i = L
                    break
                L += 1
            if R & 1:
                R -= 1
                if self.segment_tree[R] == x:
                    i = R
                    break
            L >>= 1
            R >>= 1
        while i < self.N:
            if self.segment_tree[i] == self.segment_tree[i << 1]:
                i <<= 1
            else:
                i <<= 1
                i |= 1
        i -= self.N
        return i

    def Bisect_Right(self, l=None, f=None):
        if l == self.N:
            return self.N
        if l == None:
            l = 0
        if f(self.Fold(l, self.N)):
            return self.N
        l += self.N
        v = self.e
        while True:
            while l % 2 == 0:
                l >>= 1
            vv = self.f(v, self.segment_tree[l])
            if f(vv):
                v = vv
                l += 1
                if 2 * self.N == l << self.N.bit_length() - l.bit_length() + 1:
                    return self.N
            else:
                while l < self.N:
                    l <<= 1
                    vv = self.f(v, self.segment_tree[l])
                    if f(vv):
                        v = vv
                        l += 1
                return l - self.N

    def Bisect_Left(self, r=None, f=None):
        if r == 0:
            return 0
        if r == None:
            r = self.N
        if f(self.Fold(0, r)):
            return 0
        r += self.N
        v = self.e
        while True:
            r -= 1
            while r > 1 and r % 2:
                r >>= 1
            vv = self.f(self.segment_tree[r], v)
            if f(vv):
                v = vv
                if 2 * self.N == r << self.N.bit_length() - r.bit_length() + 1:
                    return 0
            else:
                while r < self.N:
                    r = 2 * r + 1
                    vv = self.f(self.segment_tree[r], v)
                    if f(vv):
                        v = vv
                        r -= 1
                return r + 1 - self.N

    def __str__(self):
        return '[' + ', '.join(map(str, self.segment_tree[self.N:])) + ']'
(N, M) = map(int, readline().split())
D = list(map(int, readline().split()))
H = list(map(int, readline().split()))
STL = [0] * N
STR = [0] * N
for i in range(1, N):
    STL[i] = STL[i - 1] + D[i - 1]
for i in range(N - 2, -1, -1):
    STR[i] += STR[i + 1] + D[i]
for i in range(N):
    STL[i] += H[i] * 2
    STR[i] += H[i] * 2
ST0 = [0] * N
ST1 = [0] * N
for i in range(1, N):
    ST0[i] = ST0[i - 1] - D[i - 1]
    ST1[i] = ST1[i - 1] + D[i - 1]
for i in range(N):
    ST0[i] += H[i] * 2
    ST1[i] += H[i] * 2
inf = 1 << 60
STL = Segment_Tree(N, max, -inf, STL)
STR = Segment_Tree(N, max, -inf, STR)
ST0 = Segment_Tree(N, max, -inf, ST0)
ST1 = Segment_Tree(N, max, -inf, ST1)
d = D[N - 1]
for i in range(M):
    (a, b) = map(int, readline().split())
    ans = -inf
    a -= 1
    if a <= b:
        ans = max(ans, STL.Fold(0, a) + STR.Fold(b, N) + d)
        if 2 <= a:
            x = ST1.Fold_Index(0, a)
            ans = max(ans, ST0.Fold(0, x) + ST1[x])
            ans = max(ans, ST0[x] + ST1.Fold(x + 1, a))
        if b + 2 <= N:
            x = ST1.Fold_Index(b, N)
            ans = max(ans, ST0.Fold(b, x) + ST1[x])
            ans = max(ans, ST0[x] + ST1.Fold(x + 1, N))
    else:
        x = ST1.Fold_Index(b, a)
        ans = max(ans, ST0.Fold(b, x) + ST1[x])
        ans = max(ans, ST0[x] + ST1.Fold(x + 1, a))
    print(ans)