「CF52C」Circular RMQ

更好的阅读体验

Portal

Portal1: Codeforces

Portal2: Luogu

Description

You are given circular array \(a_0, a_1, \cdots, a_{n - 1}\). There are two types of operations with it:

  • \(\textrm{inc}(lf, rg, v)\) — this operation increases each element on the segment \([lf, rg]\) (inclusively) by \(v\);

  • \(\textrm{rmq}(lf, rg)\) — this operation returns minimal value on the segment \([lf, rg]\) (inclusively).

Assume segments to be circular, so if \(n = 5\) and \(lf = 3, rg = 1\), it means the index sequence: \(3, 4, 0, 1\).

Write program to process given sequence of operations.

Input

The first line contains integer \(n (1 \le n \le 200000)\). The next line contains initial state of the array: \(a_0, a_1, \cdots, a_{n - 1} ( -10^6 \le ai \le 10^6)\), \(a_i\) are integer. The third line contains integer \(m (0 \le m \le 200000)\), \(m\) — the number of operartons. Next \(m\) lines contain one operation each. If line contains two integer \(lf, rg (0 \le lf, rg \le n - 1)\) it means rmq operation, it contains three integers \(lf, rg, v (0 \le lf, rg \le n - 1; -10^6 \le v \le 10^6)\) — inc operation.

Output

For each rmq operation write result for it. Please, do not use %lld specificator to read or write \(64\)-bit integers in C++. It is preffered to use cout (also you may use %I64d).

Sample Input

4
1 2 3 4
4
3 0
3 0 -1
0 1
2 1

Sample Output

1
0
0

Solution

我们可以用线段树来解决区间RMQ问题,我们在线段树上维护一个最小值与懒标记,这样问题就解决了。

读入的时候我们可以判断后面一个字符是不是空格,可以直接在快速读入里判断,这样就可以判断出一行有三个数还是两个数。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

const int MAXN = 200005;
int n, m, l, r, val, a[MAXN];
bool opt;
namespace Segtree {
    #define ls rt << 1
    #define rs rt << 1 | 1
    typedef long long LL;
    const LL Seg_INF = 1e18;
    const int Seg_MAXN = 1000005;
    struct SMT {
        LL Min, tag;
    } tree[Seg_MAXN];
    inline void build(int rt, int l, int r) {//建立线段树
        if (l == r) {
            tree[rt].Min = a[l];
            return ;
        }
        int mid = l + r >> 1;
        build(ls, l, mid);
        build(rs, mid + 1, r);
        tree[rt].Min = min(tree[ls].Min, tree[rs].Min);
    }
    inline void update(int rt, int l, int r, int ansl, int ansr, int val) {//线段树修改
        if (ansl <= l && r <= ansr) {
            tree[rt].tag += val;
            return ;
        }
        int mid = l + r >> 1;
        if (ansl <= mid) update(ls, l, mid, ansl, ansr, val);
        if (mid < ansr) update(rs, mid + 1, r, ansl, ansr, val);
        tree[rt].Min = min(tree[ls].Min + tree[ls].tag, tree[rs].Min + tree[rs].tag);
    }
    inline LL query(int rt, int l, int r, int ansl, int ansr) {//线段树查询
        if (ansl <= l && r <= ansr) return tree[rt].Min + tree[rt].tag;
        int mid = l + r >> 1;
        LL ret = Seg_INF;
        if (ansl <= mid) ret = min(ret, query(ls, l, mid, ansl, ansr));
        if (mid < ansr) ret = min(ret, query(rs, mid + 1, r, ansl, ansr));
        return ret + tree[rt].tag;
    }
}

using namespace Segtree;

inline int read() {
    opt = 0;
    char ch = getchar();
    int x = 0, f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if (ch == ' ') opt = 1;//判断空格
    return x * f;
}
int main() {
    n = read();
    for (int i = 1; i <= n; i++)
        a[i] = read();
    build(1, 1, n);
    m = read();
    for (int i = 1; i <= m; i++) {
        l = read(); r = read(); l++; r++;
        if (!opt) {
            if (l <= r) printf("%lld\n", query(1, 1, n, l, r)); else printf("%lld\n", min(query(1, 1, n, l, n), query(1, 1, n, 1, r)));
        } else {
            val = read();
            if (l <= r) update(1, 1, n, l, r, val); else {
                update(1, 1, n, l, n, val);
                update(1, 1, n, 1, r, val);
            }
        }
    }
    return 0;
}
posted @ 2019-10-04 20:03  XiaoHuang666  阅读(173)  评论(0编辑  收藏  举报