0
点赞
收藏
分享

微信扫一扫

[线段树]打字练习记录

m逆光生长 2022-02-16 阅读 33

1.P3372 【模板】线段树 1

裸板子

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 10;
int tree[N << 2], lazy[N << 2];

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

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

void build(int rt, int l, int r){
    lazy[rt] = 0;
    if(l == r){
        cin >> tree[rt];
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
    push_up(rt);
}

void update_part(int rt, int l, int r, int L, int R, int val){
    if(l >= L && r <= R){
        lazy[rt] += val;
        tree[rt] += val * (r - l + 1);
        return;
    }
    push_down(rt, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) update_part(rt << 1, l, mid, L, R, val);
    if(mid < R) update_part(rt << 1 | 1, mid + 1, r, L, R, val);
    push_up(rt);
}

int query(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R) return tree[rt];
    push_down(rt, r - l + 1);
    int mid = l + r >> 1, ans = 0;
    if(mid >= L) ans += query(rt << 1, l, mid, L, R);
    if(mid < R) ans += query(rt << 1 | 1, mid + 1, r, L, R);
    return ans;
}


inline void solve(){
    int n, m; cin >> n >> m;
    build(1, 1, n);
    while(m--){
        int op, x, y, k; cin >> op >> x >> y;
        if(op == 1){
            cin >> k;
            update_part(1, 1, n, x, y, k);
        }
        else cout << query(1, 1, n, x, y) << endl;
    }
}   

signed main(){
    solve();
    return 0;
}

2.P3373 【模板】线段树 2

维护乘法标记和加法标记,注意运算顺序和取模操作。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 10;
int MOD = 571373;
int tree[N << 2], lazy_mul[N << 2], lazy_add[N << 2];

inline int binpow(int x, int n, int MOD, int ret = 1){
    for(x %= MOD; n; n >>= 1, (x *= x) %= MOD) if(n & 1) (ret *= x) %= MOD;
    return ret == 1 ? 0 : ret;
}

inline void push_up(int rt){ tree[rt] = (tree[rt << 1] + tree[rt << 1 | 1]) % MOD; }

inline void push_down(int rt, int m){
    lazy_mul[rt << 1] = (lazy_mul[rt << 1] * lazy_mul[rt]) % MOD;
    lazy_mul[rt << 1 | 1] = (lazy_mul[rt << 1 | 1] * lazy_mul[rt]) % MOD;
    lazy_add[rt << 1] = (lazy_add[rt << 1] * lazy_mul[rt] + lazy_add[rt]) % MOD;
    lazy_add[rt << 1 | 1] = (lazy_add[rt << 1 | 1] * lazy_mul[rt] + lazy_add[rt]) % MOD;
    tree[rt << 1] = (tree[rt << 1] * lazy_mul[rt] + lazy_add[rt] * (m - (m >> 1))) % MOD;
    tree[rt << 1 | 1] = (tree[rt << 1 | 1] * lazy_mul[rt] + lazy_add[rt] * (m >> 1)) % MOD;  
    lazy_add[rt] = 0, lazy_mul[rt] = 1;
}

void build(int rt, int l, int r){
    lazy_add[rt] = 0, lazy_mul[rt] = 1;
    if(l == r){
        cin >> tree[rt];
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
    push_up(rt);
}

void update_add(int rt, int l, int r, int L, int R, int val){
    if(l >= L && r <= R){
        (lazy_add[rt] += val) %= MOD;
        (tree[rt] += val * (r - l + 1)) %= MOD;
        return;
    }
    push_down(rt, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) update_add(rt << 1, l, mid, L, R, val);
    if(mid < R) update_add(rt << 1 | 1, mid + 1, r, L, R, val);
    push_up(rt);
}

void update_mul(int rt, int l, int r, int L, int R, int val){
    if(l >= L && r <= R){
        (lazy_add[rt] *= val) %= MOD;
        (lazy_mul[rt] *= val) %= MOD;
        (tree[rt] *= val) %= MOD;
        return;
    }
    push_down(rt, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) update_mul(rt << 1, l, mid, L, R, val);
    if(mid < R) update_mul(rt << 1 | 1, mid + 1, r, L, R, val);
    push_up(rt);
}

int query(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R) return tree[rt];
    push_down(rt, r - l + 1);
    int mid = l + r >> 1, ans = 0;
    if(mid >= L) (ans += query(rt << 1, l, mid, L, R)) %= MOD;
    if(mid < R) (ans += query(rt << 1 | 1, mid + 1, r, L, R)) %= MOD;
    return ans;
}

inline void solve(){
    int n, m; cin >> n >> m >> MOD;
    build(1, 1, n);
    while(m--){
        int op, x, y, k; cin >> op >> x >> y;
        if(op == 1){
            cin >> k;
            update_mul(1, 1, n, x, y, k);
        }
        else if(op == 2){
            cin >> k;
            update_add(1, 1, n, x, y, k);
        }
        else{
            cout << query(1, 1, n, x, y) << endl;
        }
    }
}

signed main(){
    ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
    solve();
    return 0;
}

3.P2023 [AHOI2009] 维护序列

根上题一模一样,继续练习打字

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5 + 10;
int tree[N << 2], lazy_mul[N << 2], lazy_add[N << 2], MOD = INT_MAX;

inline void push_up(int rt){ tree[rt] = (tree[rt << 1] + tree[rt << 1 | 1]) % MOD; }

inline void push_down(int rt, int m){
    lazy_mul[rt << 1] = (lazy_mul[rt << 1] * lazy_mul[rt]) % MOD;
    lazy_mul[rt << 1 | 1] = (lazy_mul[rt << 1 | 1] * lazy_mul[rt]) % MOD;
    lazy_add[rt << 1] = (lazy_add[rt << 1] * lazy_mul[rt] + lazy_add[rt]) % MOD;
    lazy_add[rt << 1 | 1] = (lazy_add[rt << 1 | 1] * lazy_mul[rt] + lazy_add[rt]) % MOD;
    tree[rt << 1] = (tree[rt << 1] * lazy_mul[rt] + lazy_add[rt] * (m - (m >> 1))) % MOD;
    tree[rt << 1 | 1] = (tree[rt << 1 | 1] * lazy_mul[rt] + lazy_add[rt] * (m >> 1)) % MOD;
    lazy_add[rt] = 0, lazy_mul[rt] = 1;
}

void build(int rt, int l, int r){
    lazy_add[rt] = 0, lazy_mul[rt] = 1;
    if(l == r){
        cin >> tree[rt];
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
    push_up(rt);
}

void update_mul(int rt, int l, int r, int L, int R, int val){
    if(l >= L && r <= R){
        (lazy_mul[rt] *= val) %= MOD;
        (lazy_add[rt] *= val) %= MOD;
        (tree[rt] *= val) %= MOD;
        return;
    }
    push_down(rt, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) update_mul(rt << 1, l, mid, L, R, val);
    if(mid < R) update_mul(rt << 1 | 1, mid + 1, r, L, R, val);
    push_up(rt);
}

void update_add(int rt, int l, int r, int L, int R, int val){
    if(l >= L && r <= R){
        (lazy_add[rt] += val) %= MOD;
        (tree[rt] += val * (r - l + 1)) %= MOD;
        return;
    }
    push_down(rt, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) update_add(rt << 1, l, mid, L, R, val);
    if(mid < R) update_add(rt << 1 | 1, mid + 1, r, L, R, val);
    push_up(rt);
}

int query(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R) return tree[rt];
    push_down(rt, r - l + 1);
    int mid = l + r >> 1, ans = 0;
    if(mid >= L) (ans += query(rt << 1, l, mid, L, R)) %= MOD;
    if(mid < R) (ans += query(rt << 1 | 1, mid + 1, r, L, R)) %= MOD;
    return ans;
}

inline void solve(){
    int n, p; cin >> n >> MOD;
    build(1, 1, n);
    int m; cin >> m;
    while(m--){
        int op, x, y, k; cin >> op >> x >> y;
        if(op == 1){
            cin >> k;
            update_mul(1, 1, n, x, y, k);
        }
        else if(op == 2){
            cin >> k;
            update_add(1, 1, n, x, y, k);
        }
        else cout << query(1, 1, n, x, y) << endl;
    }
}

signed main(){
    solve();
    return 0;
}

4.P1047 [NOIP2005 普及组] 校门外的树

线段树维护清零操作+根节点查询,继续练习打字

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

const int N = 1e4 + 10;
int tree[N << 2], lazy[N << 2];

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

inline void push_down(int rt){
    if(lazy[rt]) return;
    lazy[rt << 1] = lazy[rt], lazy[rt << 1 | 1] = lazy[rt];
    tree[rt << 1] = lazy[rt], tree[rt << 1 | 1] = lazy[rt];
    lazy[rt] = 1;
}

void build(int rt, int l, int r){
    lazy[rt] = 1;
    if(l == r){
        tree[rt] = 1;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
    push_up(rt);
}

void update(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R){
        lazy[rt] = 0;
        tree[rt] = 0;
        return;
    }
    push_down(rt);
    int mid = l + r >> 1;
    if(mid >= L) update(rt << 1, l, mid, L, R);
    if(mid < R) update(rt << 1 | 1, mid + 1, r, L, R);
    push_up(rt);
}


inline void solve(){
    int n, m; cin >> n >> m; n += 1;
    build(1, 1, n);
    while(m--){
        int u, v; cin >> u >> v;
        update(1, 1, n, u + 1, v + 1);
    }
    cout << tree[1] << endl;
}

signed main(){
    solve();
    return 0;
}

5.P1276 校门外的树(增强版)

建立两颗线段树,分别维护树的棵树、树+树苗的棵数,最后答案就是:

  1. 树苗数 = 总数(树+树苗棵数) - 树的棵数
  2. 砍掉的树苗数 = 总砍掉的数目 - 砍掉树的数目
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int tree[N << 2][2], lazy[N << 2][2], cnt1 = 0, cnt2 = 0;

inline void push_up(int rt, int i){ tree[rt][i] = tree[rt << 1][i] + tree[rt << 1 | 1][i]; }

inline void push_down(int rt, int i, int m){
    if(!lazy[rt][i]) return;
    else if(lazy[rt][i] == 1){
        lazy[rt << 1][i] = lazy[rt << 1 | 1][i] = 1;
        tree[rt << 1][i] = (m - (m >> 1)), tree[rt << 1 | 1][i] = (m >> 1);
    }
    else{
        lazy[rt << 1][i] = lazy[rt << 1 | 1][i] = -1;
        tree[rt << 1][i] = tree[rt << 1 | 1][i] = 0;
    }
    lazy[rt][i] = 0;
}

void build(int rt, int l, int r){
    lazy[rt][1] = lazy[rt][0] = 0;
    if(l == r){
        tree[rt][0] = tree[rt][1] = 1;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
    push_up(rt, 0), push_up(rt, 1);
}

void CutTree(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R){
        cnt1 += tree[rt][0], cnt2 += tree[rt][1];
        lazy[rt][0] = lazy[rt][1] = -1;
        tree[rt][0] = tree[rt][1] = 0;
        return;
    }
    push_down(rt, 0, r - l + 1), push_down(rt, 1, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) CutTree(rt << 1, l, mid, L, R);
    if(mid < R) CutTree(rt << 1 | 1, mid + 1, r, L, R);
    push_up(rt, 1), push_up(rt, 0);
}

void PlantTree(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R){
        lazy[rt][1] = 1;
        tree[rt][1] = (r - l + 1);
        return;
    }
    push_down(rt, 1, r - l + 1);
    int mid = l + r >> 1;
    if(mid >= L) PlantTree(rt << 1, l, mid, L, R);
    if(mid < R) PlantTree(rt << 1 | 1, mid + 1, r, L, R);
    push_up(rt, 1); 
}

inline void solve(){
    int n, m; cin >> n >> m; n += 1;
    build(1, 1, n);
    while(m--){
        int op, l, r; cin >> op >> l >> r;
        if(op == 0) CutTree(1, 1, n, l + 1, r + 1);
        else PlantTree(1, 1, n, l + 1, r + 1);
        /*DEBUG
        cout << "DEBUG " << tree[1][1] << " " << tree[1][0] << endl;
        cout << "DEBUG " << cnt2 << " " << cnt1 << endl;*/
    }
    cout << tree[1][1] - tree[1][0] << endl;
    cout << cnt2 - cnt1 << endl;
}

signed main(){
    solve();
    return 0;
}

6.P1531 I Hate It

单点查询区间修改,ZKW也可写。

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

#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r

const int N = 2e5 + 10;
int tree[N << 2];

inline void push_up(int rt){ tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]); }

void build(int rt, int l, int r){
    if(l == r){
        cin >> tree[rt];
        return;
    }
    int mid = l + r >> 1;
    build(lson), build(rson);
    push_up(rt);
}

void update(int rt, int l, int r, int pos, int val){
    if(l == r){
        tree[rt] = max(val, tree[rt]);
        return;
    }
    int mid = l + r >> 1;
    if(mid >= pos) update(lson, pos, val);
    else update(rson, pos, val);
    push_up(rt);
}

int query_part(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R) return tree[rt];
    int mid = l + r >> 1, ans = 0;
    if(mid >= L) ans = max(ans, query_part(lson, L, R));
    if(mid < R) ans = max(ans, query_part(rson, L, R)); 
    return ans;
}

inline void solve(){
    int n, m; cin >> n >> m;
    build(1, 1, n);
    while(m--){
        char op; int x, y;
        cin >> op >> x >> y;
        if(op == 'Q') cout << query_part(1, 1, n, x, y) << endl;
        else update(1, 1, n, x, y);
    }
}

signed main(){
    solve();
    return 0;
}

7.P5057 [CQOI2006]简单题

区间翻转,实际上可以合并 l a z y lazy lazy t r e e tree tree数组,因为一模一样。。。

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

const int N = 1e5 + 10;
int tree[N << 2], lazy[N << 2];

#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r

inline void push_down(int rt){
    if(!lazy[rt]) return;
    tree[rt << 1] ^= 1, tree[rt << 1 | 1] ^= 1;
    lazy[rt << 1] ^= 1, lazy[rt << 1 | 1] ^= 1;
    lazy[rt] = 0;
}

void update(int rt, int l, int r, int L, int R){
    if(l >= L && r <= R){
        tree[rt] ^= 1, lazy[rt] ^= 1;
        return;
    }
    int mid = l + r >> 1;
    if(mid >= L) update(lson, L, R);
    if(mid < R) update(rson, L, R);
}

int query(int rt, int l, int r, int pos){
    if(l == r) return tree[rt];
    int mid = l + r >> 1;
    push_down(rt);
    if(mid >= pos) return query(lson, pos);
    else return query(rson, pos);
}

inline void solve(){
    int n, m; cin >> n >> m;
    while(m--){
        int op, x, y; cin >> op >> x;
        if(op == 1){
            cin >> y;
            update(1, 1, n, x, y);
        }
        else cout << query(1, 1, n, x) << endl;
    }
}

signed main(){
    solve();
    return 0;
}

8.P4588 [TJOI2018]数学计算

建立初始全为 1 1 1的线段树,叶子节点维护乘数,需要乘的时候将当前位置更新为乘数,需要除的时候将该操作的位置更新为 1 1 1,然后查询直接输出根节点即可。

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int N = 1e5 + 10;
int tree[N << 2], MOD = 0;

#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r

inline void push_up(int rt){ tree[rt] = (tree[rt << 1] * tree[rt << 1 | 1]) % MOD; }

void build(int rt, int l, int r){
    if(l == r){
        tree[rt] = 1;
        return;
    }
    int mid = l + r >> 1;
    build(ls), build(rs);
    push_up(rt);
}

void update(int rt, int l, int r, int pos, int val){
    if(l == r){
        tree[rt] = val;
        return;
    }
    int mid = l + r >> 1;
    if(mid >= pos) update(ls, pos, val);
    else update(rs, pos, val);
    push_up(rt);
}

int query(int rt, int l, int r, int pos){
    if(l == r) return tree[rt];
    int mid = l + r >> 1;
    if(mid <= pos) return query(ls, pos);
    else return query(rs, pos);
}

inline void solve(){
    int q; std::cin >> q >> MOD;
    build(1, 1, q);
    int cnt = 0;
    for(int i = 1; i <= q; i++){
        int op, m; std::cin >> op >> m;
        if(op == 1){
            update(1, 1, q, i, m);
            std::cout << tree[1] % MOD << endl;
        }
        else{
            update(1, 1, q, m, 1);
            std::cout << tree[1] % MOD << endl;
        }
    }
}

signed main(){
    int t = 0; std::cin >> t;
    while(t--) solve();
    return 0;
}
举报

相关推荐

0 条评论