Skip to content
Runtime
Go back

线段树

Edit page

总结

可以完成的操作:

1.单点、区间修改

2.单点、区间查询

单点修改线段树(SegmentTree)

template<class Info>
struct SegmentTree {
    int n;
    std::vector<Info> info;
    SegmentTree() : n(0) {}
    SegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    SegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << std::__lg(n), Info());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};

struct Info {
    int sum=0;
};

Info operator+(Info a, Info b) {
    Info c;
    c.sum=a.sum+b.sum;
    return c;
}

区间修改线段树(LazySegmentTree)

区间修改时,节点增加的应该是

sum += t.add * len;

完整Code

template<class Info, class Tag>
struct LazySegmentTree {
    int n;
    std::vector<Info> info;
    std::vector<Tag> tag;
    LazySegmentTree() : n(0) {}
    LazySegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    LazySegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << std::__lg(n), Info());
        tag.assign(4 << std::__lg(n), Tag());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void apply(int p, const Tag &v) {
        info[p].apply(v);
        tag[p].apply(v);
    }
    void push(int p) {
        apply(2 * p, tag[p]);
        apply(2 * p + 1, tag[p]);
        tag[p] = Tag();
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        push(p);
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        push(p);
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    void rangeApply(int p, int l, int r, int x, int y, const Tag &v) {
        if (l >= y || r <= x) {
            return;
        }
        if (l >= x && r <= y) {
            apply(p, v);
            return;
        }
        int m = (l + r) / 2;
        push(p);
        rangeApply(2 * p, l, m, x, y, v);
        rangeApply(2 * p + 1, m, r, x, y, v);
        pull(p);
    }
    void rangeApply(int l, int r, const Tag &v) {
        return rangeApply(1, 0, n, l, r, v);
    }
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        push(p);
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        push(p);
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};
 
struct Tag {
    int add = 0;
    void apply(Tag t) { //两个懒标记结合
        add += t.add;
    }
};
 
struct Info {
    int sum = 0;
    int len = 1;
    void apply(Tag t) { //懒标记作用到信息上
        sum += t.add * len;
    }
};
Info operator+(Info a, Info b) {
    Info c;
    c.sum = a.sum + b.sum;
    c.len = a.len + b.len;
    return c;
}

例题

SegmentTree

【模板】树状数组 2

地址

struct Info {
    long long sum = 0; // 存储区间和
};
Info operator+(const Info& a, const Info& b) {
    return Info(a.sum + b.sum);
}
void solve() {
    int n, q;
    cin>>n>>q;
    vector<Info> a(n);
    for(int i=0;i<n;i++) cin>>a[i].sum;

    SegmentTree<Info> segTree(a);
    while(q--){
        int op;cin>>op;
        if(op==1){
            int x,k;
            cin>>x>>k;
            x--;
            a[x].sum+=k;
            segTree.modify(x, Info(a[x].sum));
        }else{
            int x,y;
            cin>>x>>y;
            x--;y--;
            Info ans=segTree.rangeQuery(x,y+1);
            cout<<ans.sum<<"\n";
        }
    }
}

LazySegmentTree

【模板】线段树 1

地址

struct Tag {
    int add = 0;
    void apply(Tag t) { //两个懒标记结合
        add += t.add;
    }
};
 
struct Info {
    int sum = 0;
    int len = 1;
    void apply(Tag t) { //懒标记作用到信息上
        sum += t.add * len;
    }
};
Info operator+(Info a, Info b) {
    Info c;
    c.sum = a.sum + b.sum;
    c.len = a.len + b.len;
    return c;
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n, q;
    cin >> n >> q;

    vector<Info> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i].sum;
        a[i].len = 1;
    }

    LazySegmentTree<Info, Tag> seg(a);

    while(q--){
        int op;cin>>op;
        if(op==1){
            int l,r,v;cin>>l>>r>>v;
            seg.rangeApply(l-1,r,Tag{v});
        }else{
            int l,r;cin>>l>>r;
            cout<<seg.rangeQuery(l-1,r).sum<<'\n';
        }
    }
}

【模板】线段树 2

地址

struct Tag {
    Z add = 0;
	Z mul = 1;
    void apply(Tag t) { //两个懒标记结合
		mul *= t.mul;
		add = add * t.mul + t.add;
    }
};
 
struct Info {
    Z sum = 0;
    int len = 1;
    void apply(Tag t) { //懒标记作用到信息上       
		sum = sum * t.mul + t.add * len;
    }
};
Info operator+(Info a, Info b) {
    Info c;
    c.sum = a.sum + b.sum;
    c.len = a.len + b.len;
    return c;
}
void SINGLE_TEST()
{
    int n,q,m;
	cin>>n>>q>>m;
	vector<Info> a(n+1);
	for(int i=1;i<=n;i++){
		cin>>a[i].sum;
	}   
	LazySegmentTree<Info,Tag> tr(a);
	while (q--)
	{
		int op,x,y;
		cin>>op>>x>>y;
		if(op==1){
			Z k;cin>>k;
			Tag t;
			t.mul = k;
			tr.rangeApply(x,y+1,t);
		}else if(op==2){
			Z k;cin>>k;
			Tag t;
			t.add = k;
			tr.rangeApply(x,y+1,t);
		}else{
			cout<<tr.rangeQuery(x,y+1).sum<<'\n';
		}
	}
}

Edit page
Share this post on:

Previous Post
2024牛客暑期多校训练营1
Next Post
平面直角坐标系的斜线移动