模板 - 线段树

区间线段树:

const int MAXM=100000;
int a[MAXM+5];
ll st[(MAXM<<2)+5],lazy[(MAXM<<2)+5];

inline void push_up(int o) {
    st[o]=st[o<<1]+st[o<<1|1];
}

inline void push_down(int o,int l,int r) {
    if(lazy[o]) {
        lazy[o<<1]+=lazy[o];
        lazy[o<<1|1]+=lazy[o];
        int m=(l+r)>>1;
        st[o<<1]+=lazy[o]*(m-l+1);
        st[o<<1|1]+=lazy[o]*(r-m);
        lazy[o]=0;
    }
}

void build(int o,int l,int r) {
    if(l==r)
        st[o]=a[l];
    else {
        int m=(l+r)>>1;
        build(o<<1,l,m);
        build(o<<1|1,m+1,r);
        push_up(o);
    }
    lazy[o]=0;
}

void update(int o,int l,int r,int a,int b,ll v) {
    if(a<=l&&r<=b) {
        lazy[o]+=v;
        st[o]+=v*(r-l+1);
        return;
    } else {
        push_down(o,l,r);
        int m=(l+r)>>1;
        if(a<=m)
            update(o<<1,l,m,a,b,v);
        if(b>=m+1)
            update(o<<1|1,m+1,r,a,b,v);
        push_up(o);
    }
}

ll query(int o,int l,int r,int a,int b) {
    if(a<=l&&r<=b) {
        return st[o];
    } else {
        push_down(o,l,r);
        int m=(l+r)>>1;
        ll ans=0;
        if(a<=m)
            ans=ans+query(o<<1,l,m,a,b);
        if(b>=m+1)
            ans=ans+query(o<<1|1,m+1,r,a,b);
        return ans;
    }
}

单点线段树就把lazy相关的直接给去掉就行了。

单点线段树:

const int MAXM=100000;
int a[MAXM+5];
int st[(MAXM<<2)+5];

inline void push_up(int o) {
    st[o]=st[o<<1]+st[o<<1|1];
}

void build(int o,int l,int r) {
    if(l==r){
        st[o]=a[l];
    }
    else {
        int m=(l+r)>>1;
        build(o<<1,l,m);
        build(o<<1|1,m+1,r);
        push_up(o);
    }
}

void update(int o,int l,int r,int x,int v) {
    if(l==r) {
        st[o]=v;
        return;
    } else {
        int m=(l+r)>>1;
        if(x<=m)
            update(o<<1,l,m,x,v);
        else if(x>=m+1)
            update(o<<1|1,m+1,r,x,v);
        push_up(o);
    }
}

int query(int o,int l,int r,int a,int b) {
    if(a<=l&&r<=b) {
        return st[o];
    } else {
        int m=(l+r)>>1;
        int ans=0;
        if(a<=m)
            ans=query(o<<1,l,m,a,b);
        if(b>=m+1)
            ans+=query(o<<1|1,m+1,r,a,b);
        return ans;
    }
}

区间修改,有两个tag的先后顺序,好像是钦定一个tag影响另一个tag。现在是钦定mul影响add,也就是每次mul操作都会把add也更新。

其实是钦定结合优先级高的tag影响结合优先级低的tag。比如

x
x+v1
(x+v1)*v2

实际上把加法tag也要变成v1*v2

但是

x
xv1
x
v1+v2

加法tag并不会影响乘法tag

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXM = 100000 + 5;
int a[MAXM];
ll sum[MAXM << 2], add[MAXM << 2], mul[MAXM << 2];

int mod;

inline void push_up(int o) {
    sum[o] = (sum[o << 1] + sum[o << 1 | 1]) % mod;
}

inline void push_down(int o, int l, int r) {
    if(mul[o] != 1) {
        mul[o << 1] = mul[o << 1] * mul[o] % mod;
        mul[o << 1 | 1] = mul[o << 1 | 1] * mul[o] % mod;
        add[o << 1] = add[o << 1] * mul[o] % mod;
        add[o << 1 | 1] = add[o << 1 | 1] * mul[o] % mod;
        sum[o << 1] = sum[o << 1] * mul[o] % mod;
        sum[o << 1 | 1] = sum[o << 1 | 1] * mul[o] % mod;
        mul[o] = 1;
    }
    if(add[o] != 0) {
        add[o << 1] = (add[o << 1] + add[o]) % mod;
        add[o << 1 | 1] = (add[o << 1 | 1] + add[o]) % mod;
        int m = (l + r) >> 1;
        sum[o << 1] = (sum[o << 1]  + add[o] * (m - l + 1)) % mod;
        sum[o << 1 | 1] = (sum[o << 1 | 1] + add[o] * (r - m) ) % mod;
        add[o] = 0;
    }
}

void build(int o, int l, int r) {
    if(l == r)
        sum[o] = a[l];
    else {
        int m = (l + r) >> 1;
        build(o << 1, l, m);
        build(o << 1 | 1, m + 1, r);
        push_up(o);
    }
    mul[o] = 1, add[o] = 0;
}

void update_add(int o, int l, int r, int a, int b, ll v) {
    if(a <= l && r <= b) {
        add[o] = (add[o] + v) % mod;
        sum[o] = (sum[o] + v * (r - l + 1) % mod) % mod;
        return;
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        if(a <= m)
            update_add(o << 1, l, m, a, b, v);
        if(b >= m + 1)
            update_add(o << 1 | 1, m + 1, r, a, b, v);
        push_up(o);
    }
}

void update_mul(int o, int l, int r, int a, int b, ll v) {
    if(a <= l && r <= b) {
        mul[o] = mul[o] * v % mod;
        add[o] = add[o] * v % mod;
        sum[o] = sum[o] * v % mod;
        return;
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        if(a <= m)
            update_mul(o << 1, l, m, a, b, v);
        if(b >= m + 1)
            update_mul(o << 1 | 1, m + 1, r, a, b, v);
        push_up(o);
    }
}

ll query(int o, int l, int r, int a, int b) {
    if(a <= l && r <= b) {
        return sum[o];
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        ll ans = 0;
        if(a <= m)
            ans = query(o << 1, l, m, a, b);
        if(b >= m + 1)
            ans = (ans + query(o << 1 | 1, m + 1, r, a, b)) % mod;
        return ans;
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    scanf("%d%d%d", &n, &m, &mod);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    build(1, 1, n);
    for(int i = 1; i <= m; ++i) {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if(op == 1) {
            int k;
            scanf("%d", &k);
            update_mul(1, 1, n, x, y, k);
        } else if(op == 2) {
            int k;
            scanf("%d", &k);
            update_add(1, 1, n, x, y, k);
        } else {
            printf("%lld\n", query(1, 1, n, x, y));
        }
    }
}
posted @ 2019-06-17 14:57  韵意  阅读(240)  评论(0编辑  收藏  举报