草庐IT

模板-线段树

随便写点什么 2023-03-28 原文

模板

单点修改的线段树

template<typename Avalue, typename Tvalue, // 序列类型,线段树类型
    void (*set)(Tvalue&, Avalue),  // 设置线段树初值
    Tvalue (*op)(Tvalue, Tvalue),    // 线段树合并
    Tvalue (*c)(Tvalue, Tvalue)>    // 线段树修改
struct lazysegment_tree {
    std::vector<Tvalue> tree;
    std::vector<Avalue> array;
    size_t size;

#define LCH id * 2
#define RCH id * 2 + 1

    lazysegment_tree() = default;
    lazysegment_tree(size_t n, std::vector<Avalue>& a)
     : tree((n + 1) << 2), array(a), size(n) {
        build(1, 1, size);
    }

    void build(size_t n, std::vector<Avalue>& a) {
        tree.resize((n + 1) << 2);
        size = n;
        array = a;
        build(1, 1, size);
    }
    void build(int id, int l, int r) {
        if (l == r) {
            set(tree[id], array[l]);
            return;
        }
        int mid = (l + r) >> 1;
        build(LCH, l, mid);
        build(RCH, mid + 1, r);
        tree[id] = op(tree[LCH], tree[RCH]);
    }
    void clear() {
        std::vector<Tvalue> tmp1;
        std::vector<Avalue> tmp3;
        tmp1.swap(tree);
        tmp3.swap(array);
        size = 0;
    }
    void modify(int id, int l, int r, int pos, Tvalue value) {
        if (pos <= l && r <= pos) {
            tree[id] = c(tree[id], value);
            return;
        } 
        int mid = (l + r) >> 1;
        if (pos <= mid) modify(LCH, l ,mid, pos, value);
        if (pos > mid) modify(RCH, mid + 1, r, pos, value);
        tree[id] = op(tree[LCH], tree[RCH]);
    }
    Tvalue query(int id, int l, int r, int pl, int pr) {
        if (pl <= l && r <= pr) {
            return tree[id];
        }
        int mid = (l + r) >> 1;
        if (pr <= mid) return query(LCH, l, mid, pl, pr);
        else if (pl > mid) return query(RCH, mid + 1, r, pl, pr);
        return op(query(LCH, l, mid, pl, pr), query(RCH, mid + 1, r, pl, pr));
    }
    template<bool (*cmp)(Tvalue, Tvalue)>
    int lower_bound(int id, int l, int r, int pl, int pr, Tvalue d) {
        if (pl <= l && r <= pr) {
            int mid = (l + r) >> 1;
            if (!cmp(tree[id], d)) return -1;
            else if (l == r) return l;
            else if (cmp(tree[LCH], d)) return lower_bound<cmp>(LCH, l, mid, pl, pr, d);
            else return lower_bound<cmp>(RCH, mid + 1, r, pl, pr, d);
        }
        int mid = (l + r) >> 1, lans = -1, rans = -1;
        if (pl <= mid) lans = lower_bound<cmp>(LCH, l, mid, pl, pr, d);
        if (pr > mid) rans = lower_bound<cmp>(RCH, mid + 1, r, pl, pr, d);
        return (lans != -1 ? lans : rans);
    }

    void modify(int pos, Tvalue value) {
        modify(1, 1, size, pos, value);
    }
    Tvalue query(int pos) {
        return query(1, 1, size, pos, pos);
    }
    Tvalue query(int left, int right) {
        return query(1, 1, size, left, right);
    }
    template<bool (*cmp)(Tvalue, Tvalue)>
    int lower_bound(int left, int right, Tvalue d) {
        return lower_bound<cmp>(1, 1, size, left, right, d);
    }
};

初始化

// 区间最大值, 单点赋值
using ll = long long;
struct tv{
    ll max;
};
void set(tv& a, ll b) {
    a = { b };
}
tv op(tv a, tv b) {
    return { std::max(a.max, b.max) };
}
tv c(tv a, tv b) {
    return b;
}
bool cmp(tv a, tv b) {
    return a.max >= b.max;
}
// 或者 lazysegment_tree<ll, tv, set, op, c> seg(n, a);
lazysegment_tree<ll, tv, set, op, c> seg;
seg.build(n, a);

模板第一个参数 Avalue, 为序列 a 的值 类型。
第二个参数 Tvalue, 为 线段树值 的类型。
第三个参数void (*set)(Tvalue&, Avalue), 为线段树 赋初始值 的函数指针。
第四个参数Tvalue (*op)(Tvalue, Tvalue), 为线段树 合并两个段 的函数指针。
第五个参数Tvalue (*c)(Tvalue, Tvalue), 为线段树 单点修改 的函数指针。

可以全局创建,之后通过 build(n, a) 来构造线段树,也可以直接通过构造函数来创建局部变量,参数与 build 相同。

通过 clear 可以清空线段树。

修改

modify(pos, value), value 的类型与 线段树值 一致。

查询

返回值为 线段树的值 类型。

query(left, right), 区间查询。

query(pos), 单点查询。

线段树上二分

lower_bound<cmp>(left, right, d), 查找区间中第一个满足条件的下标,不存在得到 -1

cmp 为函数指针 bool (*cmp)(Tvalue, Tvalue),查找区间中第一个下标 pos 满足 cmp(a[pos], d) == true

区间修改线段树

template<typename Avalue, typename Tvalue, typename Tag, // 序列类型,线段树类型, 标记类型
    void (*set)(Tvalue&, Avalue),  // 设置线段树初值
    Tvalue (*op)(Tvalue, Tvalue),   // 线段树合并
    void (*tag)(Tvalue&, Tag&, Tag), // 下传标记
    Tag (*e)()>    // 清空标记(标记初值)
struct lazysegment_tree {
    std::vector<Tvalue> tree;
    std::vector<Tag> lazy;
    std::vector<Avalue> array;
    size_t size;

#define LCH id * 2
#define RCH id * 2 + 1

    lazysegment_tree() = default;
    lazysegment_tree(size_t n, std::vector<Avalue>& a)
     : tree((n + 1) << 2), lazy((n + 1) << 2, e()), array(a), size(n) {
        build(1, 1, size);
    }

    void build(size_t n, std::vector<Avalue>& a) {
        tree.resize((n + 1) << 2);
        lazy.resize((n + 1) << 2, e());
        size = n;
        array = a;
        build(1, 1, size);
    }
    void build(int id, int l, int r) {
        if (l == r) {
            set(tree[id], array[l]);
            return;
        }
        int mid = (l + r) >> 1;
        build(LCH, l, mid);
        build(RCH, mid + 1, r);
        tree[id] = op(tree[LCH], tree[RCH]);
    }
    void clear() {
        std::vector<Tvalue> tmp1;
        std::vector<Tag> tmp2;
        std::vector<Avalue> tmp3;
        tmp1.swap(tree);
        tmp2.swap(lazy);
        tmp3.swap(array);
        size = 0;
    }
    void pushdown(int id) {
        if (lazy[id] == e()) return;
        tag(tree[LCH], lazy[LCH], lazy[id]);
        tag(tree[RCH], lazy[RCH], lazy[id]);
        lazy[id] = e();
    }
    void modify(int id, int l, int r, int pl, int pr, Tag value) {
        if (pl <= l && r <= pr) {
            tag(tree[id], lazy[id], value);
            return;
        } 
        pushdown(id);
        int mid = (l + r) >> 1;
        if (pl <= mid) modify(LCH, l ,mid, pl, pr, value);
        if (pr > mid) modify(RCH, mid + 1, r, pl, pr, value);
        tree[id] = op(tree[LCH], tree[RCH]);
    }
    Tvalue query(int id, int l, int r, int pl, int pr) {
        if (pl <= l && r <= pr) {
            return tree[id];
        }
        pushdown(id);
        int mid = (l + r) >> 1;
        if (pr <= mid) return query(LCH, l, mid, pl, pr);
        else if (pl > mid) return query(RCH, mid + 1, r, pl, pr);
        return op(query(LCH, l, mid, pl, pr), query(RCH, mid + 1, r, pl, pr));
    }
    template<bool (*cmp)(Tvalue, Tvalue)>
    int lower_bound(int id, int l, int r, int pl, int pr, Tvalue d) {
        if (pl <= l && r <= pr) {
            int mid = (l + r) >> 1;
            if (!cmp(tree[id], d)) return -1;
            else if (l == r) return l;
            pushdown(id);
            if (cmp(tree[LCH], d)) return lower_bound<cmp>(LCH, l, mid, pl, pr, d);
            else return lower_bound<cmp>(RCH, mid + 1, r, pl, pr, d);
        }
        pushdown(id);
        int mid = (l + r) >> 1, lans = -1, rans = -1;
        if (pl <= mid) lans = lower_bound<cmp>(LCH, l, mid, pl, pr, d);
        if (pr > mid) rans = lower_bound<cmp>(RCH, mid + 1, r, pl, pr, d);
        return (lans != -1 ? lans : rans);
    }

    void modify(int left, int right, Tag value) {
        modify(1, 1, size, left, right, value);
    }
    Tvalue query(int pos) {
        return query(1, 1, size, pos, pos);
    }
    Tvalue query(int left, int right) {
        return query(1, 1, size, left, right);
    }
    template<bool (*cmp)(Tvalue, Tvalue)>
    int lower_bound(int left, int right, Tvalue d) {
        return lower_bound<cmp>(1, 1, size, left, right, d);
    }
};

初始化

// 区间和, 区间加
using ll = long long;
struct tv{
    ll sum;
    int size;
};
void set(tv& a, ll b) {
    a = { b, 1 };
}
tv op(tv a, tv b) {
    return { a.sum + b.sum, a.size + b.size };
}
void tag(tv& a, ll& b, ll c) {
    if (c == 0) return;
    a.sum += c * a.size;
    b += c;
}
ll e() {
    return 0;
}
// 或者 lazysegment_tree<ll, tv, ll, set, op, tag, e> seg(n, a);
lazysegment_tree<ll, tv, ll, set, op, tag, e> seg;
seg.build(n, a);

模板第一个参数 Avalue, 为序列 a 的值 类型。
第二个参数 Tvalue, 为 线段树值 的类型。
第三个参数 Tag, 为 标记 的类型。
第四个参数void (*set)(Tvalue&, Avalue), 为线段树 赋初始值 的函数指针。
第五个参数Tvalue (*op)(Tvalue, Tvalue), 为线段树 合并两个段 的函数指针。
第六个参数void (*tag)(Tvalue&, Tag&, Tag), 为线段树 设置标记 的函数指针。
第七个参数Tag (*e)(), 为线段树 标记的初始值 的函数指针。

可以全局创建,之后通过 build(n, a) 来构造线段树,也可以直接通过构造函数来创建局部变量,参数与 build 相同。

通过 clear 可以清空线段树。

修改

modify(left, right, value), value 的类型与 标记 一致。

查询

返回值为 线段树的值 类型。

query(left, right), 区间查询。

query(pos), 单点查询。

线段树上二分

lower_bound<cmp>(left, right, d), 查找区间中第一个满足条件的下标,不存在得到 -1

cmp 为函数指针 bool (*cmp)(Tvalue, Tvalue),查找区间中第一个下标 pos 满足 cmp(a[pos], d) == true

其他

P3372 【模板】线段树 1

OI-wiki

有关模板-线段树的更多相关文章

  1. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  2. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

  3. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

    所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

  4. ruby - 如何通过Middleman安装和使用Slim模板引擎 - 2

    一般来说,我是Middleman和ruby​​的新手。我已经安装了Ruby我已经安装了Middleman和gem以使其运行。我需要使用slim而不是默认的模板系统。所以我安装了Slimgem。Slim的网站只说我需要'slim'才能让它工作。中间人网站说我只需要在config.rb文件中添加模板引擎,但是没有给出例子...对于没有ruby​​背景的人来说,这没有帮助。我在git上找了几个config.rb,它们都有:require'slim'和#Setslim-langoutputstyleSlim::Engine.set_default_options:pretty=>true#Se

  5. ruby-on-rails - 如何将变量值插入 ERB 模板中的 HTML 标签? - 2

    我有一个偏爱:如何将像o.office这样的值插入到属性中?value="#{o.office}"无效。 最佳答案 'type='text'/>或者你可以使用表单助手 关于ruby-on-rails-如何将变量值插入ERB模板中的HTML标签?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6172174/

  6. ruby - 输出液体模板中的可用对象和属性 - 2

    有没有办法在liquidtemplate中输出(用于调试/信息目的)可用对象和对象属性??也就是说,假设我正在使用jekyll站点生成工具,并且我在我的index.html模板中(据我所知,这是一个液体模板)。它可能看起来像这样{%forpostinsite.posts%}{{post.date|date_to_string}}»{{post.title}}{%endfor%}是否有任何我可以使用的模板标签会告诉我/输出名为post的变量在此模板(以及其他模板)中可用。此外,是否有任何模板标签可以告诉我post对象具有键date、title、url、摘录、永久链接等

  7. ruby - 在公差范围内确定两条线段是否属于同一线段的最有效方法是什么? - 2

    编辑:更改了标题。我对两个部分是否相同不太感兴趣,而是如果它们在一定的公差范围内彼此共线。如果是这样,那么这些线应该聚集在一起作为一个单独的线段。编辑:我想有一个简短的说法:我试图以一种有效的方式将相似的线段聚集在一起。假设我有线段f(fx0,fy0)和(fx1,fy1)和g(gx0,gy0)和(gx1,gy1)这些来自计算机视觉算法边缘检测器之类的东西,在某些情况下,两条线基本相同,但由于像素容差而被视为两条不同的线。有几种情况f和g共享完全相同的端点,例如:f=(0,0),(10,10)g=(0,0),(10,10)f和g共享大致相同的端点和大致相同的长度,例如:f=(0,0.01

  8. python - 图灵完备模板引擎 - 2

    很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭11年前。哪些模板引擎/模板语言是图灵完备的?到目前为止,我听说过这些:FreeMarker(用java实现)MovableTypes模板语言(perl)xslt:-(Cheetah(Python语言)聪明(PHP)还有其他的(特别是用perl实现的)吗?Ps:不要浪费时间向我解释MVC,以及为什么图灵完整模板不好,以及为什么这不是一个有用的比较点:)

  9. ruby - 迭代液体模板中的数组 - 2

    我知道我可以用这段代码迭代liquid模板中的数组:{%foriteminmyarray%}{{item.label}}但是我怎样才能得到我的项目在数组中的索引呢? 最佳答案 根据"LiquidforDesigners"liquid的github部分...forloop.length#=>lengthoftheentireforloopforloop.index#=>indexofthecurrentiterationforloop.index0#=>indexofthecurrentiteration(zerobased)forl

  10. ruby - 液体模板贴图过滤器 - 2

    究竟如何使用Liquid中的map过滤器?我在Jekyll中使用它。---my_array:[apple,banana,orage]my_map:hello:worldfoo:barmy_string:"howdoesthiswork?"---{{page.my_map|map...}}这就是我迷路的地方。我似乎无法在文档或任何其他在线网站上找到任何关于它的用法示例。顺便说一下,我还不懂Ruby,所以sourcecode我也不清楚。来自filtertests看起来下面应该产生一些东西,但在GitHub上,我什么也没得到:{{site.posts|map:'title'|array_to

随机推荐