线段树 (模板)
功能
用\(log_2n\)时间复杂度对区间进行加减乘求和等等操作的数据结构。
实现
主要参考的是oi_wiki教程。
记录一下板子(即HDU1166 - 敌兵布阵的代码)
注意事项
- 开4倍空间,再大点更好。
- 叶结点不要pushdown,否则可能会越界(因为只开了4倍空间)
//L,R均代表待处理的区间。
//lef,rig均代表范围。
//单点更新(覆盖),区间求和
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const ll maxn = 50001;
ll sum[maxn << 2];
ll lazy[maxn << 2];
void pushup(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void pushdown(int rt, int len) {
if(lazy[rt]) {
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
sum[rt << 1] += lazy[rt << 1] * (len - (len >> 1));
sum[rt << 1 | 1] += lazy[rt << 1 | 1] * (len >> 1);
lazy[rt] = 0;
}
}
void update(int L, int R, int lef, int rig, int rt, ll val) {
if(lef >= L && rig <= R) {
sum[rt] += val * (rig - lef + 1);
lazy[rt] += val;
return ;
}
pushdown(rt, rig - lef + 1);
int mid = (lef + rig) / 2;
if(L <= mid) update(L, R, lef, mid, rt << 1, val);
if(R > mid) update(L, R, mid + 1, rig, rt << 1 | 1, val);
pushup(rt);
}
void build(int lef, int rig, int rt) {
if(lef > rig) return ;
lazy[rt] = 0;
if(lef == rig) {
ll tmp;
scanf("%lld", &tmp);
sum[rt] = tmp;
return ;
}
int mid = (lef + rig) / 2;
build(lef, mid, rt << 1);
build(mid + 1, rig, rt << 1 | 1);
pushup(rt);
}
ll query(int L, int R, int lef, int rig, int rt) {
if(lef >= L && rig <= R) return sum[rt];
pushdown(rt, rig - lef + 1);
int mid = (lef + rig) / 2;
ll res = 0;
if(L <= mid) res += query(L, R, lef, mid, rt << 1);
if(R > mid) res += query(L, R, mid + 1, rig, rt << 1 | 1);
return res;
}
int main() {
int T = 0;
char q[10];
scanf("%d", &T);
for(int cases = 1; cases <= T; cases++) {
printf("Case %d:\n", cases);
int n;
scanf("%d", &n);
build(1, n, 1);
while(1) {
scanf("%s", q);
if(!strcmp(q, "Add")) {
int pos;
ll val;
scanf("%d%lld", &pos, &val);
update(pos, pos, 1, n, 1, val);
}
else if(!strcmp(q, "Sub")) {
int pos;
ll val;
scanf("%d%lld", &pos, &val);
update(pos, pos, 1, n, 1, -val);
}
else if(!strcmp(q, "Query")) {
int L, R;
scanf("%d%d", &L, &R);
printf("%lld\n", query(L, R, 1, n, 1));
}
else if(!strcmp(q, "End")) break;
}
}
}
其它
对于大范围的区间操作,可以用离散化的技巧。但是这主要处理以后线段树就不支持在线操作了。
似乎有一种动态开点的方法可以解决这问题,有时间补上。