題目描述
從前有一個貿易市場,在一位執政官到來之前都是非常繁榮的,自從他來了之後,釋出了一系列奇怪的政令,導致貿易市場的衰落。
有 \(n\) 個商販,從\(0 \sim n - 1\) 編號,每個商販的商品有一個價格\(a_i\),有兩種政令:
\(l, r, c\),對於\(i \in [l, r], a_i \leftarrow a_i + c\)
\(l, r, d\),對於\(i \in [l, r], a_i \leftarrow \lfloor {a_i}/{d} \rfloor\)
現在有一個外鄉的旅客想要了解貿易市場的資訊,有兩種詢問方式:
給定 \(l, r\),求\(\min_{i \in [l, r]} a_i\)
給定 \(l, r\),求\(\sum_{i\in [l, r]} a_i\)
輸入格式
第一行為兩個空格隔開的整數 \(n, q\) 分別表示商販個數和政令 \(+\) 詢問個數。
第二行包含 \(n\) 個由空格隔開的整數\(a_0 \sim a_{n - 1}\)
接下來 \(q\) 行,每行表示一個操作,第一個數表示操作編號\(1 \sim 4\),接下來的輸入和問題描述一致。
輸出格式
對於每個 \(3\)、\(4\) 操作,輸出詢問答案。
樣例
樣例輸入
10 10
-5 -4 -3 -2 -1 0 1 2 3 4
1 0 4 1
1 5 9 1
2 0 9 3
3 0 9
4 0 9
3 0 1
4 2 3
3 4 5
4 6 7
3 8 9
樣例輸出
-2
-2
-2
-2
0
1
1
資料範圍與提示
對於 \(30\%\) 的資料,$n, q \leq 10 ^ 3 $;
對於 \(60\%\) 的資料,保證資料隨機;
對於 \(100\%\) 的資料,\(1 \leq n, q \leq 10 ^ 5, 0 \leq l \leq r \leq n - 1, c \in [-10 ^ {4}, 10 ^ 4], d \in [2, 10 ^ 9]\)
分析
對於區間加、區間求和、區間求最小值的操作,像正常的線段樹那樣維護即可
對於區間除的操作,因為題目中要求向下取整,所以不能直接給整體除一個數
但是我們可以把除法轉化為減法,把除以一個數變成減去一個數
這樣,當一個區間內減去的數相同時,我們就可以給整體打一個標記
判斷區間減去的數是否相同只需要判斷區間最大值和區間最小值減去的值是否相同
如果不相同就一直下放,直到相同為止
這樣的話我們再記錄一個最大值就可以解決了
時間複雜度:\(O(可過)\)
程式碼
#include <cstdio>
#include <algorithm>
#include <cmath>
#define rg register
inline int read() {
rg int x = 0, fh = 1;
rg char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
fh = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * fh;
}
const int maxn = 1e5 + 5;
int a[maxn], n, q;
struct trr {
int l, r, laz, mmin, mmax, siz;
long long sum;
} tr[maxn << 2];
void push_up(int da) {
tr[da].mmax = std::max(tr[da << 1].mmax, tr[da << 1 | 1].mmax);
tr[da].mmin = std::min(tr[da << 1].mmin, tr[da << 1 | 1].mmin);
tr[da].sum = tr[da << 1].sum + tr[da << 1 | 1].sum;
}
void push_down(int da) {
if (tr[da].laz) {
tr[da << 1].laz += tr[da].laz;
tr[da << 1 | 1].laz += tr[da].laz;
tr[da << 1].sum += 1LL * tr[da << 1].siz * tr[da].laz;
tr[da << 1 | 1].sum += 1LL * tr[da << 1 | 1].siz * tr[da].laz;
tr[da << 1].mmax += tr[da].laz;
tr[da << 1 | 1].mmax += tr[da].laz;
tr[da << 1].mmin += tr[da].laz;
tr[da << 1 | 1].mmin += tr[da].laz;
tr[da].laz = 0;
}
}
void build(int da, int l, int r) {
tr[da].l = l, tr[da].r = r, tr[da].siz = r - l + 1;
if (tr[da].l == tr[da].r) {
tr[da].mmin = tr[da].mmax = a[l];
tr[da].sum = a[l];
return;
}
rg int mids = (tr[da].l + tr[da].r) >> 1;
build(da << 1, l, mids);
build(da << 1 | 1, mids + 1, r);
push_up(da);
}
void ad(int da, int l, int r, int val) {
if (tr[da].l >= l && tr[da].r <= r) {
tr[da].laz += val;
tr[da].sum += 1LL * val * tr[da].siz;
tr[da].mmin += val;
tr[da].mmax += val;
return;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
if (l <= mids)
ad(da << 1, l, r, val);
if (r > mids)
ad(da << 1 | 1, l, r, val);
push_up(da);
}
int cxmin(int da, int l, int r) {
if (tr[da].l >= l && tr[da].r <= r) {
return tr[da].mmin;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1, nans = 2147483647;
if (l <= mids)
nans = std::min(nans, cxmin(da << 1, l, r));
if (r > mids)
nans = std::min(nans, cxmin(da << 1 | 1, l, r));
return nans;
}
long long cxsum(int da, int l, int r) {
if (tr[da].l >= l && tr[da].r <= r) {
return tr[da].sum;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
rg long long nans = 0;
if (l <= mids)
nans += cxsum(da << 1, l, r);
if (r > mids)
nans += cxsum(da << 1 | 1, l, r);
return nans;
}
void cf(int da, int l, int r, int val) {
if (tr[da].l >= l && tr[da].r <= r) {
rg int now1 = floor((double)tr[da].mmin / val) - tr[da].mmin;
rg int now2 = floor((double)tr[da].mmax / val) - tr[da].mmax;
if (tr[da].l == tr[da].r) {
tr[da].mmin = floor((double)tr[da].mmin / val);
tr[da].sum = tr[da].mmax = tr[da].mmin;
} else if (now1 == now2) {
tr[da].mmin += now1;
tr[da].mmax += now1;
tr[da].laz += now1;
tr[da].sum += 1LL * tr[da].siz * now1;
} else {
push_down(da);
cf(da << 1, l, r, val);
cf(da << 1 | 1, l, r, val);
push_up(da);
}
return;
}
push_down(da);
rg int mids = (tr[da].l + tr[da].r) >> 1;
if (l <= mids)
cf(da << 1, l, r, val);
if (r > mids)
cf(da << 1 | 1, l, r, val);
push_up(da);
}
int main() {
n = read(), q = read();
for (rg int i = 1; i <= n; i++) {
a[i] = read();
}
build(1, 1, n);
rg int aa, bb, cc, dd;
for (rg int i = 1; i <= q; i++) {
aa = read(), bb = read(), cc = read();
bb++, cc++;
if (aa == 1) {
dd = read();
ad(1, bb, cc, dd);
} else if (aa == 2) {
dd = read();
cf(1, bb, cc, dd);
} else if (aa == 3) {
printf("%d\n", cxmin(1, bb, cc));
} else {
printf("%lld\n", cxsum(1, bb, cc));
}
}
return 0;
}