文章目录
4 数据结构
4.1 树状数组
4.1.1 普通树状数组
仅支持单点修改区间查询。
const int maxn = 1e5 + 10;
int tree[maxn];
int lb(int x) { return x & -x; }
int read(int x) {
int tot = 0;
for (int i = x; i; i -= lb(i)) {
tot += tree[i];
}
return tot;
}
void add(int num, int x) {
for (int i = x; i <= n; i += lb(i)) {
tree[i] += num;
}
}
4.1.2 普通二维树状数组
const int maxn = 1010;
int tree[maxn][maxn];
int n, m;
int lb(int x) { return x & -x; }
int read(int x, int y) {
int tot = 0;
for (int i = x; i; i -= lb(i)) {
for (int j = y; j; j -= lb(j))
tot += tree[i][j];
}
return tot;
}
void add(int num, int x, int y) {
for (int i = x; i <= n; i += lb(i)) {
for (int j = y; j <= m; j += lb(j)) {
tree[i][j] += num;
}
}
}
4.1.3 树状数组维护区间最大、最小值
维护区间[1,x]的:
const int maxn = 1e5 + 10;
int c[maxn], n, r[maxn], a[maxn];
inline int lb(int x) { return x & -x; }
int query(int x) {
int tot = 0;
for (; x; x -= lb(x))
tot = max(tot, c[x]);
return tot;
}
void update(int x, int v) {
for (; x <= n; x += lb(x)) {
c[x] = max(c[x], v);
int t = x - lb(x);
for (int y = x - 1; y && y - lb(y) >= t; y -= lb(y))
c[x] = max(c[x], c[y]);
}
}
4.2 线段树
4.2.1 维护区间最值,区间修改
const int maxn = 1e5 + 10;
struct tree {
int left, right;
ll sum, add, maxm, minm;
} c[maxn << 2];
ll a[maxn];
void build(int id, int l, int r) {
c[id].left = l;
c[id].right = r;
if (l == r) {
c[id].maxm = c[id].minm = c[id].sum = a[l];
c[id].add = 0;
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
c[id].maxm = max(c[id << 1].maxm, c[id << 1 | 1].maxm);
c[id].minm = min(c[id << 1].minm, c[id << 1 | 1].minm);
c[id].sum = c[id << 1].sum + c[id << 1 | 1].sum;
}
void pushdown(int id) {
c[id << 1].sum += (c[id << 1].right - c[id << 1].left + 1) * c[id].add;
c[id << 1].minm += c[id].add;
c[id << 1].maxm += c[id].add;
c[id << 1].add += c[id].add;
c[id << 1 | 1].sum += (c[id << 1 | 1].right - c[id << 1 | 1].left + 1) * c[id].add;
c[id << 1 | 1].minm += c[id].add;
c[id << 1 | 1].maxm += c[id].add;
c[id << 1 | 1].add += c[id].add;
c[id].add = 0;
}
void update(int id, int pos, ll v) {
if (c[id].left == c[id].right)c[id].sum = c[id].maxm = c[id].minm = v;
else {
int mid = (c[id].left + c[id].right) >> 1;
if (pos <= mid)update(id << 1, pos, v);
else update(id << 1 | 1, pos, v);
c[id].sum = c[id << 1].sum + c[id << 1 | 1].sum;
c[id].maxm = max(c[id << 1].maxm, c[id << 1 | 1].maxm);
c[id].minm = min(c[id << 1].minm, c[id << 1 | 1].minm);
}
}
ll query_max(int id, int l, int r) {
if (c[id].left == l && c[id].right == r)return c[id].maxm;
int mid = (c[id].left + c[id].right) >> 1;
if (c[id].add)pushdown(id);
if (r <= mid)return query_max(id << 1, l, r);
else if (l > mid)return query_max(id << 1 | 1, l, r);
else return max(query_max(id << 1, l, mid), query_max(id << 1 | 1, mid + 1, r));
}
ll query_min(int id, int l, int r) {
if (c[id].left == l && c[id].right == r)return c[id].minm;
int mid = (c[id].left + c[id].right) >> 1;
if (c[id].add)pushdown(id);
if (r <= mid)return query_min(id << 1, l, r);
else if (l > mid)return query_min(id << 1 | 1, l, r);
else return min(query_min(id << 1, l, mid), query_min(id << 1 | 1, mid + 1, r));
}
void update(int id, int l, int r, ll v) {
if (c[id].left > r || c[id].right < l)return;
if (c[id].left >= l && c[id].right <= r) {
c[id].add += v;
c[id].sum += (c[id].right - c[id].left + 1) * v;
return;
}
if (c[id].add)pushdown(id);
update(id << 1, l, r, v);
update(id << 1 | 1, l, r, v);
c[id].sum = c[id << 1].sum + c[id << 1 | 1].sum;
}
ll query_sum(int id, int l, int r) {
if (r < c[id].left || l > c[id].right)return 0;
if (c[id].left >= l && c[id].right <= r) {
return c[id].sum;
}
if (c[id].add)pushdown(id);
ll ans = query_sum(id << 1, l, r) + query_sum(id << 1 | 1, l, r);
c[id].sum = c[id << 1].sum + c[id << 1 | 1].sum;
return ans;
}
4.2.2 动态开点线段树
const int maxn = (1e6 + 10) * 51;
const int inf = 1e9 + 10;
int ls[maxn], rs[maxn], cnt;
struct tree {
int left, right, mmin;
} c[maxn];
void build(int id, int l, int r) {
c[id].left = l;
c[id].right = r;
c[id].mmin = inf;
ls[id] = rs[id] = 0;
}
void update(int id, int pos, int v) {
if (c[id].left == c[id].right)c[id].mmin = min(c[id].mmin, v);
else {
int mid = (c[id].left + c[id].right) >> 1;
if (pos <= mid) {
if (ls[id] == 0) {
ls[id] = cnt;
build(cnt, c[id].left, mid);
++cnt;
}
update(ls[id], pos, v);
c[id].mmin = min(c[id].mmin, c[ls[id]].mmin);
} else {
if (rs[id] == 0) {
rs[id] = cnt;
build(cnt, mid + 1, c[id].right);
++cnt;
}
update(rs[id], pos, v);
c[id].mmin = min(c[id].mmin, c[rs[id]].mmin);
}
}
}
bool query_min(int id, int l, int r, int ck) {
if (c[id].left == l && c[id].right == r)return (ck >= c[id].mmin);
if (c[id].mmin > ck)return 0;
int mid = (c[id].left + c[id].right) >> 1;
if (r <= mid) {
if (ls[id] != 0)return query_min(ls[id], l, r, ck);
} else if (l > mid) {
if (rs[id] != 0)return query_min(rs[id], l, r, ck);
} else {
if (ls[id] != 0 && query_min(ls[id], l, mid, ck))return 1;
else if (rs[id] != 0 && query_min(rs[id], mid + 1, r, ck))return 1;
}
return 0;
}