zoukankan      html  css  js  c++  java
  • 线段树 新)

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

    区间可分:整个区间的信息用于更新子区间的信息(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]);
    }
  • 相关阅读:
    递归——8月4日
    练习:结构体、枚举类型——8月3日
    结构体、枚举类型——8月3日
    数组——7月25日
    类的复习——7月25日
    异常保护——7月25日
    类以及练习——7月25日
    javase学习小结二
    javase学习小结一
    产生随机数的方法
  • 原文地址:https://www.cnblogs.com/Maxx-el/p/13782486.html
Copyright © 2011-2022 走看看