模板·双标记线段树

又写了一遍线段树, 用了更多的模板元template, 实在是太方便了.对于我这种脑子不太灵活的选手很友好.
不用纠结到底是int还是long long了.

双标记线段树的主要注意的问题是如何合并标记.
像这道题就是加的标记和乘的标记.
线段树2
什么?你说我的线段树跑的很慢?没问题呀, 考试的时候我又不这样写...

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int N = 500005;
using namespace std;

long long mod;
template<typename Int>
struct BaseNode {
    Int val, len, f1, f2;
    BaseNode *ls, *rs;
    BaseNode(Int _v = 0, BaseNode *_ls = nullptr, 
             BaseNode *_rs = nullptr, Int _f1 = 1, Int _f2 = 0, Int _len = 0):
        val(_v), ls(_ls), rs(_rs), f1(_f1), f2(_f2), len(_len) { }
    void update() {
        val = (ls->val + rs->val) % mod;
        len = ls->len + rs->len;
    }
    void Merge(Int k1, Int k2) {
        f1 = f1 * k1 % mod, f2 = f2 * k1 % mod + k2,
        val = val * k1 % mod + k2 * len % mod,
        val %= mod, k1 %= mod, k2 %= mod;
    }
    template<typename Pair>
    void Merge(Pair P) {
        Merge(P.first, P.second);
    }
    void Down() {
        if (f1 or f2) ls->Merge(f1, f2), rs->Merge(f1, f2), f1 = 1, f2 = 0;
    }
    template<typename Integar>
    void F(Integar p) {
        val = p, len = 1;
    }
};
#define new_Node() new Node()

template<typename Int>
Int Merge(Int a, Int b) {
    return (a + b) % mod;
}

template<typename Node, typename Int>
class Tree {
    int n;
    Node *root;
#define LS l, mid, node->ls
#define RS mid + 1, r, node->rs
    template<typename Integar>
    void build(int l, int r, Node *node, Integar *A) {
        if (l == r) 
            return node->F(A[l]);
        int mid = l + r >> 1;
        node->ls = new_Node();
        node->rs = new_Node();
        build(LS, A), build(RS, A);
        node->update();
    }
    template<typename STRUCT>
    void addition(int l, int r, Node *node, int L, int R, STRUCT k) {
        if (l >= L and r <= R)
            return node->Merge(k);
        node->Down();
        int mid = l + r >> 1;
        if (L <= mid) addition(LS, L, R, k);
        if (R >  mid) addition(RS, L, R, k);
        node->update();
    }
    Int Query(int l, int r, Node *node, int L, int R) {
        if (l >= L and r <= R)
            return node->val;
        node->Down();
        int mid = l + r >> 1;
        Int res = 0;
        if (L <= mid) res = Merge(res, Query(LS, L, R));
        if (R >  mid) res = Merge(res, Query(RS, L, R));
        return res;
    }
  public:
    Tree(int _n) : n(_n), root(new_Node()) {}
    template<typename Integar>
    void build(Integar *A) {
        build(1, n, root, A);
    }
    template<typename STRUCT>
    void addition(int L, int R, STRUCT k) {
        addition(1, n, root, L, R, k);
    }
    Int Query(int L, int R) {
        return Query(1, n, root, L, R);
    }
};

int A[N];
int main () {
    int n, m;
    scanf("%d%d%d", &n, &m, &mod);
    Tree<BaseNode<long long>, long long>* T = 
        new Tree<BaseNode<long long>, long long>(n);
    for (int i = 1; i <= n; i += 1) scanf("%d", &A[i]);
    T->build(A);
    while (m--) {
        int opt, x, y, k;
        scanf("%d%d%d", &opt, &x, &y);
        if (opt == 1) {
            scanf("%d", &k);
            T->addition(x, y, make_pair(k, 0));
        } else if (opt == 2) {
            scanf("%d", &k);
            T->addition(x, y, make_pair(1, k));
        } else {
            printf("%lld\n", T->Query(x, y));
        }
    }
    return 0;
}
posted @ 2018-11-07 21:33  Grary  阅读(286)  评论(0编辑  收藏  举报
博客园 首页 私信博主 编辑 关注 管理 新世界