练习名称:ITMO Academy: pilot course » Segment Tree
练习链接:Segment Tree, part 1, Step1, Practice
cf官方的线段树专题练习
A. Segment Tree for the Sum
单点修改,区间和查询
#include <bits/stdc++.h>
#define lson (u << 1)
#define rson (u << 1 | 1)
using LL = long long;
using namespace std;
const int N = 1e5 + 6;
int a[N];
struct node{
int l, r;
LL v;
}tr[N << 2];
void pushup(int u){
tr[u].v = tr[lson].v + tr[rson].v;
}
void build(int u, int l, int r){
if(l == r) tr[u] = {l, r, a[l]};
else{
tr[u] = {l, r};
int mid = l + r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int d){
if(tr[u].l == x && x == tr[u].r) tr[u].v = d;
else{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(lson, x, d);
else modify(rson, x, d);
pushup(u);
}
}
LL query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
else{
int mid = tr[u].l + tr[u].r >> 1;
LL ans = 0;
if(l <= mid) ans = query(lson, l, r);
if(r > mid) ans += query(rson, l, r);
return ans;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while(m--){
int a, b, c;
cin >> a >> b >> c;
if(a == 1){
modify(1, b + 1, c);
}else{
cout << query(1, b + 1, c) << "\n";
}
}
return 0;
}
B. Segment Tree for the Minimum
单点修改,区间最小值查询
#include <bits/stdc++.h>
#define lson (u << 1)
#define rson (u << 1 | 1)
using LL = long long;
using namespace std;
const int N = 1e5 + 6;
int a[N];
struct node{
int l, r;
LL v;
}tr[N << 2];
void pushup(int u){
tr[u].v = min(tr[lson].v, tr[rson].v);
}
void build(int u, int l, int r){
if(l == r) tr[u] = {l, r, a[l]};
else{
tr[u] = {l, r};
int mid = l + r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int d){
if(tr[u].l == x && x == tr[u].r) tr[u].v = d;
else{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(lson, x, d);
else modify(rson, x, d);
pushup(u);
}
}
LL query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
else{
int mid = tr[u].l + tr[u].r >> 1;
LL ans = 0x3f3f3f3f;
if(l <= mid) ans = min(ans, query(lson, l, r));
if(r > mid) ans = min(ans, query(rson, l, r));
return ans;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while(m--){
int a, b, c;
cin >> a >> b >> c;
if(a == 1){
modify(1, b + 1, c);
}else{
cout << query(1, b + 1, c) << "\n";
}
}
return 0;
}
C. Number of Minimums on a Segment
单点修改,区间最小值及最小值数量查询
这里就要多维护一个数量,值得注意的就是根据左右子树的区间最小值,来维护区间最小值个数。
对于父节点的维护:
- 若左子节点的最小值等于右子节点的最小值,父节点的最小值就是它们,父节点的最小值数量就是左子节点的最小值数量加右子节点的最小值数量
- 若左子节点的最小值大于右子节点的最小值,父节点的最小值就是右子节点的最小值,父节点的最小值数量就是右子节点的最小值数量
- 若左子节点的最小值小于右子节点的最小值,父节点的最小值就是左子节点的最小值,父节点的最小值数量就是左子节点的最小值数量
在整个过程中如果遇到区间不在同一节点都要执行上述操作
对于最后查询数据的存储可以使用pair或者结构体,只要是二元组即可。
#include <bits/stdc++.h>
#define lson (u << 1)
#define rson (u << 1 | 1)
using LL = long long;
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 6;
int a[N];
struct node{
int l, r;
LL v, cnt;
}tr[N << 2];
void pushup(int u){
if(tr[lson].v == tr[rson].v){
tr[u].v = tr[lson].v;
tr[u].cnt = tr[lson].cnt + tr[rson].cnt;
}else if(tr[lson].v < tr[rson].v){
tr[u].v = tr[lson].v;
tr[u].cnt = tr[lson].cnt;
}else{
tr[u].v = tr[rson].v;
tr[u].cnt = tr[rson].cnt;
}
}
void build(int u, int l, int r){
if(l == r) tr[u] = {l, r, a[l], 1};
else{
tr[u] = {l, r};
int mid = tr[u].l + tr[u].r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int d){
if(tr[u].l == x && x == tr[u].r) tr[u].v = d;
else{
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(lson, x, d);
else modify(rson, x, d);
pushup(u);
}
}
PII query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return {tr[u].v, tr[u].cnt};
int mid = tr[u].l + tr[u].r >> 1;
PII ans = {0x3f3f3f3f, 0};
if(l <= mid){
PII cur = query(lson, l, r);
if(ans.first > cur.first) ans = cur;
else if(ans.first == cur.first) ans = {ans.first, ans.second + cur.second};
}
if(r > mid){
PII cur = query(rson, l, r);
if(ans.first < cur.first) return ans;
else if(ans.first > cur.first) ans = cur;
else ans = {ans.first, ans.second + cur.second};
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while(m--){
int a, b, c;
cin >> a >> b >> c;
if(a == 1){
modify(1, b + 1, c);
}else{
auto ans = query(1, b + 1, c);
cout << ans.first << " " << ans.second << "\n";
}
}
return 0;
}