线段树 新)

线段树:区间修改,区间查询,区间可分可合性

区间可分:整个区间的信息用于更新子区间的信息(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]);
}

 

posted @ 2020-10-08 19:59  .Ivorelectra  阅读(90)  评论(0编辑  收藏  举报