#线段树#LOJ 6029「雅礼集训 2017 Day1」市场

题目

在长度为\(n(n\leq 10^5)\)的数列中,
需要满足区间加,区间下取整的操作
以及能够查询区间和以及区间最小值
除数\(d\)满足\(2\leq d\leq 10^9\)
加数\(c\)满足\(-10^4\leq c\leq 10^4\)


分析

线段树,除了区间下取整,其它都挺常规的
就说区间下取整,不满足区间可加性,那显然只能从暴力入手
如果一直分治到叶子节点,时间复杂度太高,那么要找条件去提前特判
使得时间复杂度均摊\(O(nlognlog mx)\)
其中由于加数比较小,一般常数比较小
好的,那么怎样特判,那可以转换为区间减那该多好
那希望使得\(a_j-\lfloor\frac{a_j}{d}\rfloor\)相同
只要维护区间最小值和最大值,如果带进去相同,显然这一段可以被转换为区间减
然后就完成了,注意\(C++\)中的除号是向零取整,最好直接用\(\text{cmath::floor}\)


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#define rr register
using namespace std;
const int N = 100011;
typedef long long lll;
int a[N], n, Q, mn[N << 2], lazy[N << 2], mx[N << 2];
lll w[N << 2];
inline signed iut() {
    rr int ans = 0, f = 1;
    rr char c = getchar();
    while (!isdigit(c)) f = (c == '-') ? -f : f, c = getchar();
    while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
    return ans * f;
}
inline void print(lll ans) {
    if (ans < 0)
        ans = -ans, putchar('-');
    if (ans > 9)
        print(ans / 10);
    putchar(ans % 10 + 48);
}
inline signed min(int a, int b) { return a < b ? a : b; }
inline signed max(int a, int b) { return a > b ? a : b; }
inline void pup(int k) {
    w[k] = w[k << 1] + w[k << 1 | 1], mn[k] = min(mn[k << 1], mn[k << 1 | 1]),
    mx[k] = max(mx[k << 1], mx[k << 1 | 1]);
}
inline void pdown(int k, int l, int r) {
    rr int mid = (l + r) >> 1, t = lazy[k];
    lazy[k] = 0;
    w[k << 1] += t * (mid - l + 1), w[k << 1 | 1] += t * (r - mid), mn[k << 1] += t, mn[k << 1 | 1] += t,
        mx[k << 1] += t, mx[k << 1 | 1] += t, lazy[k << 1] += t, lazy[k << 1 | 1] += t;
}
inline void build(int k, int l, int r) {
    if (l == r) {
        w[k] = mn[k] = mx[k] = a[l];
        return;
    }
    rr int mid = (l + r) >> 1;
    build(k << 1, l, mid);
    build(k << 1 | 1, mid + 1, r);
    pup(k);
}
inline void update1(int k, int l, int r, int x, int y, int z) {
    if (l == x && r == y) {
        w[k] += 1ll * (r - l + 1) * z, lazy[k] += z, mn[k] += z, mx[k] += z;
        return;
    }
    if (lazy[k])
        pdown(k, l, r);
    rr int mid = (l + r) >> 1;
    if (y <= mid)
        update1(k << 1, l, mid, x, y, z);
    else if (x > mid)
        update1(k << 1 | 1, mid + 1, r, x, y, z);
    else
        update1(k << 1, l, mid, x, mid, z), update1(k << 1 | 1, mid + 1, r, mid + 1, y, z);
    pup(k);
}
inline void update2(int k, int l, int r, int x, int y, int z) {
    if (x <= l && r <= y) {
        rr int t1 = floor(1.0 * mn[k] / z);
        rr int t2 = floor(1.0 * mx[k] / z);
        rr int MN = mn[k] - t1, MX = mx[k] - t2;
        if (MN == MX) {
            mn[k] -= MN, mx[k] -= MN, lazy[k] -= MN, w[k] -= 1ll * (r - l + 1) * MN;
            return;
        }
    }
    if (lazy[k])
        pdown(k, l, r);
    rr int mid = (l + r) >> 1;
    if (x <= mid)
        update2(k << 1, l, mid, x, y, z);
    if (mid < y)
        update2(k << 1 | 1, mid + 1, r, x, y, z);
    pup(k);
}
inline lll query1(int k, int l, int r, int x, int y) {
    if (l == x && r == y)
        return w[k];
    if (lazy[k])
        pdown(k, l, r);
    rr int mid = (l + r) >> 1;
    if (y <= mid)
        return query1(k << 1, l, mid, x, y);
    else if (x > mid)
        return query1(k << 1 | 1, mid + 1, r, x, y);
    else
        return query1(k << 1, l, mid, x, mid) + query1(k << 1 | 1, mid + 1, r, mid + 1, y);
}
inline signed query2(int k, int l, int r, int x, int y) {
    if (l == x && r == y)
        return mn[k];
    if (lazy[k])
        pdown(k, l, r);
    rr int mid = (l + r) >> 1;
    if (y <= mid)
        return query2(k << 1, l, mid, x, y);
    else if (x > mid)
        return query2(k << 1 | 1, mid + 1, r, x, y);
    else
        return min(query2(k << 1, l, mid, x, mid), query2(k << 1 | 1, mid + 1, r, mid + 1, y));
}
signed main() {
    n = iut();
    Q = iut();
    for (rr int i = 1; i <= n; ++i) a[i] = iut();
    build(1, 1, n);
    for (rr int i = 1; i <= Q; ++i) {
        rr int z = iut(), l = iut() + 1, r = iut() + 1;
        switch (z) {
            case 1: {
                update1(1, 1, n, l, r, iut());
                break;
            }
            case 2: {
                update2(1, 1, n, l, r, iut());
                break;
            }
            case 3: {
                print(query2(1, 1, n, l, r)), putchar(10);
                break;
            }
            case 4: {
                print(query1(1, 1, n, l, r)), putchar(10);
                break;
            }
        }
    }
    return 0;
}
posted @ 2020-04-21 22:41  lemondinosaur  阅读(151)  评论(0编辑  收藏  举报