懶標記線段樹

Koziki發表於2024-12-05
點選檢視程式碼
// 改build ,apply ,operator + 
// 奇奇怪怪 但能用 
struct Tag{
    ll add = 0;
    void apply(Tag &t){
        add += t.add;
        return ;
    }
};

struct Info{
    ll sum = 0;
    void apply (Tag &t, int l, int r){
        sum += t.add * (r - l + 1);
        return ;
    }
};


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

struct Seg{

    int n;
    vector<Info>info;
    vector<Tag>tag;

    Seg(int n){
        info.resize(4 * n + 4);
        tag.resize(4 * n + 4);
        this -> n = n;
    }

    void down(int p, int l, int r){
        int m = (l + r) / 2;
        info[2 * p].apply(tag[p], l, m);
        info[2 * p + 1].apply(tag[p], m + 1, r);
        tag[2 * p].apply(tag[p]);
        tag[2 * p + 1].apply(tag[p]);
        tag[p] = Tag();
    }

    void merge(int p){
        info[p] = info[2 * p]+info[2 * p + 1];
    }

    void build(vector<int> & a){
        auto build = [&](auto &&self, int p, int l, int r)->void{
            if(l == r){
                info[p].sum = a[l];
                return ;
            }
            int m = (l + r) / 2;
            self(self, 2 * p, l, m);
            self(self, 2 * p + 1, m + 1, r);
            merge(p);
        };
        build(build, 1, 1, n);
    }

    Info query(int p, int l, int r, int ql, int qr){
        if(ql > r || qr < l)return Info();
        if(ql <= l && qr >= r){
            return info[p];
        }
        down(p, l, r);
        merge(p);
        int m = (l + r ) / 2;    
        return query(2 * p, l, m, ql, qr) + query(2 * p + 1, m + 1, r, ql, qr);
    }

    void modify(int p, int l, int r, int ql, int qr, int w){
        if(ql > r || qr < l)return ;
        if(ql <= l && qr >= r){
            info[p].sum += (r - l + 1) * w;
            tag[p].add += w;
            return ;
        }
        int m = (l + r) / 2;
        down(p, l, r);
        modify(2 * p, l, m, ql, qr, w);
        modify(2 * p + 1, m + 1, r, ql, qr, w);
        merge(p);
    }
};