线段树 新)
线段树:区间修改,区间查询,区间可分可合性
区间可分:整个区间的信息用于更新子区间的信息(push_down)
区间可合:两个子区间的信息可以用于更新整个区间的信息(push_up)
只有区间修改时才需要用lazy tag
//node为树上的节点编号,l,r为arr数组下标,表示当前节点node的区间范围,l == r时说明走到叶子节点了
//x,y为arr数组下标,表示待查询区间
//tree数组表示区间信息,arr数组表示单点信息
以维护区间sum,修改时+c为例:
ll arr[maxn], tree[maxn<<2], lazy[maxn<<2]; //建树 void build(int node, int l, int r) { if(l == r) {tree[node] = arr[l]; return;} int mid = (l + r) / 2; build(node * 2, l, mid); build(node * 2 + 1, mid + 1, r); tree[node] = tree[node * 2] + tree[node * 2 + 1]; } //单点查询 int query(int node, int l, int r, int x) { if(l == r) return tree[node];//此时l==r==x int ans = 0, mid = (l + r) / 2; if(x <= mid) ans += query(node * 2, l, mid, x);//=也可 if(x > mid) ans += query(node * 2 + 1, mid + 1, r, x);//=也可,else也可 return ans; } //区间查询 int query(int node, int l, int r, int x, int y) { if(x <= l && y >= r) return tree[node]; int ans = 0, mid = (l + r) / 2; if(x <= mid) ans += query(node * 2, l, mid, x, y); if(y > mid) ans += query(node * 2 + 1, mid + 1, r, x, y); return ans; } //单点修改 void update(int node, int l, int r, int x, int c) { if(l == r) {tree[node] += c; return;} int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, c); else update(node * 2 + 1, mid + 1, r, x, c); tree[node] = tree[node * 2] + tree[node * 2 + 1]; } //区间修改 void update(int node, int l, int r, int x, int y, ll c) { if(l == r) {tree[node] += c; return;} int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y, c); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c); tree[node] = tree[node * 2] + tree[node * 2 + 1]; } //懒标记 //传递lazy tag void push_down(int node, int length)//覆盖型时不需要length,且+=改为= { if(lazy[node]) { tree[2 * node] += lazy[node] * ((length + 1) / 2); tree[2 * node + 1] += lazy[node] * (length / 2); lazy[2 * node] += lazy[node]; lazy[2 * node + 1] += lazy[node]; lazy[node] = 0; } } //区间查询 ll query(int node, int l, int r, int x, int y) { if(x <= l && y >= r) return tree[node];
push_down(node, r - l + 1);//和没有lazytag相比,只多了这一句话
ll ans = 0L; int mid = (l + r) / 2; if(x <= mid) ans += query(node * 2, l, mid, x, y); if(y > mid) ans += query(node * 2 + 1, mid + 1, r, x, y); return ans; } //区间修改 void update(int node, int l, int r, int x, int y, ll c) { if(x <= l && y >= r)//没有lazytag时区间修改递归到叶子结点才返回,此处完全覆盖就返回 { tree[node] += (r - l + 1) * c; lazy[node] += c; return; }
push_down(node, r - l + 1);
int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y, c); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c); tree[node] = tree[node * 2] + tree[node * 2 + 1]; }
注意:一个点被打上lazy标记,它的tree已经被更新完了。
懒标记含义:整个区间都被操作,暂时记录在公共祖先节点上,暂时不需向下递归至叶子结点,等有需要时再push_down
维护区间max:
void build(int node, int l, int r) { if(l == r) {tree[node] = arr[l]; return;} int mid = (l + r) / 2; build(node * 2, l, mid); build(node * 2 + 1, mid + 1, r); tree[node] = max(tree[node * 2], tree[node * 2 + 1]); } int query(int node, int l, int r, int x, int y) { if(x <= l && y >= r) return tree[node]; int ans = 0, mid = (l + r) / 2; if(x <= mid) ans = query(node * 2, l, mid, x, y); if(y > mid) ans = max(ans, query(node * 2 + 1, mid + 1, r, x, y)); return ans; } void update(int node, int l, int r, int x, int c) { if(l == r) {tree[node] = c; return;} int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, c); else update(node * 2 + 1, mid + 1, r, x, c); tree[node] = max(tree[node * 2], tree[node * 2 + 1]); }