题解-LibreOJ-6029「雅礼集训 2017 Day1」市场

维护一个数据结构,支持区间加减、区间除法(下取整)、区间查询最值、区间查询总和操作。

$n \le 100000, q \le 100000$

线段树区间除法模板题。可以玄学分析复杂度。

观察到对某个区间进行除法操作后,其区间内的权值整体减小某个值,当且仅当该区间的最大元素与最小元素减小的值相等。因此区间除法可以转化为区间减法,只需判断是否满足区间减的条件即可。

注意 '/' 运算符对数字进行向零取整,并不是向下取整

实现非常简单。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson(u) node[u].l
#define rson(u) node[u].r
#define tag(u) node[u].tag
#define maxx(u) node[u].maxx
#define minn(u) node[u].minn
#define sum(u) node[u].sum

const int maxn = 100005;
const int inf = 0x3f3f3f3f;

struct Node {
int l, r, tag, minn, maxx;
ll sum;
}node[maxn << 1];
int cnt;

int N, Q, R;
int a[maxn];

inline void pushdown(int u, int l, int r) {
if (tag(u)) {
int mid = (l + r) >> 1;
int llen = mid - l + 1, rlen = r - mid;
sum(lson(u)) += 1ll * tag(u) * llen, sum(rson(u)) += 1ll * tag(u) * rlen;
minn(lson(u)) += tag(u), minn(rson(u)) += tag(u);
maxx(lson(u)) += tag(u), maxx(rson(u)) += tag(u);
tag(lson(u)) += tag(u), tag(rson(u)) += tag(u);
tag(u) = 0;
}
}

inline void pushup(int u) {
sum(u) = sum(lson(u)) + sum(rson(u));
minn(u) = min(minn(lson(u)), minn(rson(u)));
maxx(u) = max(maxx(lson(u)), maxx(rson(u)));
}

void build(int& u, int l, int r) {
u = ++cnt;
sum(u) = 0, minn(u) = inf, maxx(u) = -inf;
if (l == r) {
sum(u) = minn(u) = maxx(u) = a[l];
return;
}
int mid = (l + r) >> 1;
build(lson(u), l, mid), build(rson(u), mid + 1, r);
pushup(u);
}

void modify_range_add(int u, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr) {
tag(u) += val;
sum(u) += 1ll * val * (r - l + 1);
minn(u) += val;
maxx(u) += val;
return;
}
pushdown(u, l, r);
int mid = (l + r) >> 1;
if (ql <= mid) modify_range_add(lson(u), l, mid, ql, qr, val);
if (mid < qr) modify_range_add(rson(u), mid + 1, r, ql, qr, val);
pushup(u);
}

void modify_range_divide(int u, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr) {
int dmin = minn(u) - floor(1.0 * minn(u) / val), dmax = maxx(u) - floor(1.0 * maxx(u) / val);
if (dmin == dmax) {
tag(u) -= dmin;
sum(u) -= 1ll * dmin * (r - l + 1);
minn(u) -= dmin;
maxx(u) -= dmin;
return;
}
}
pushdown(u, l, r);
int mid = (l + r) >> 1;
if (ql <= mid) modify_range_divide(lson(u), l, mid, ql, qr, val);
if (mid < qr) modify_range_divide(rson(u), mid + 1, r, ql, qr, val);
pushup(u);
}

int query_range_min(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return minn(u);
pushdown(u, l, r);
int mid = (l + r) >> 1, ret = inf;
if (ql <= mid) ret = min(ret, query_range_min(lson(u), l, mid, ql, qr));
if (mid < qr) ret = min(ret, query_range_min(rson(u), mid + 1, r, ql, qr));
return ret;
}

ll query_range_sum(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return sum(u);
pushdown(u, l, r);
int mid = (l + r) >> 1; ll ret = 0;
if (ql <= mid) ret += query_range_sum(lson(u), l, mid, ql, qr);
if (mid < qr) ret += query_range_sum(rson(u), mid + 1, r, ql, qr);
return ret;
}

int main() {
scanf("%d%d", &N, &Q);
for (int i = 0; i < N; ++i) scanf("%d", &a[i]);
build(R, 0, N - 1);
for (int i = 1; i <= Q; ++i) {
int op, l, r, x;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) scanf("%d", &x), modify_range_add(R, 0, N - 1, l, r, x);
else if (op == 2) scanf("%d", &x), modify_range_divide(R, 0, N - 1, l, r, x);
else if (op == 3) printf("%d\n", query_range_min(R, 0, N - 1, l, r));
else printf("%lld\n", query_range_sum(R, 0, N - 1, l, r));
}
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×