[SMOJ1833]小球染色

来源:互联网 发布:linux 线程同步 编辑:程序博客网 时间:2024/05/18 15:57

这题很明显,就是要实现两种操作:区间修改和单点查询,是典型的数据结构裸题,可以用线段树解决。

因为题目没有太多好讲的,我们不妨先回顾一下线段树这个数据结构,最后再稍来点拨一下本题。
首先还是要回到本质,数据结构到底是什么?为什么 OI 的学习越到后面,要花一百多甚至几百行去编写一个数据结构?

我们来看 wikipedia 对数据结构的定义,“In computer science, a data structure is a particular(特殊的) way of organizing data in a computer so that it can be used efficiently(有效地).”
由此可见,数据结构是一种强有力的辅助手段,帮助我们更好地处理我们所拥有的数据,或在运算时大幅度提高效率。
效率这个词,在 OI 竞赛中实在是太重要了。因此也就引发了 OI 选手对数据结构的追求,以至于早就有人提出“程序=算法+数据结构”的概念。

再回到线段树来看。线段树是处理区间问题时的利器,可以参考 04 年国家集训队有两篇论文对此作了较详细的阐述。无论是单点修改、区间查询,区间修改、单点查询……线段树都可以在 O(logN) 内解决我们的需求,而能让他如此高效的“秘诀”就在于打散标记(lazy-tag)。

对一棵线段树的操作可以看成对一条线段的操作,其中每个结点对应管辖原线段中的一小段,每个结点要么没有儿子(叶子结点),要么有两个儿子。
当我们把一个区间修改之后,如果一层一层递归下去再修改儿子,显然是非常慢的,不能够符合我们对数据结构的需求,于是 lazy-tag 思想应运而生。

其精华就是:反正我只有在需要查询的时候才需要知道某一段最新的值,那么之前如果修改了某一段,就先“置之不理”,在需要进行递归的时候(无论是 update 还是 query 都好),顺便把标记打散往下带。这样一来效率就可以得到飞跃。

事实上,利用线段树解决问题,关键在于每个结点要记录什么值?
对于此题,其实就是一段区间是否为统一的颜色的问题。如果某段区间的颜色统一,那么就可以往下传。虽然可以另外加 bool 变量标记,但是把区间的颜色值赋为 0 也是一种可行的方法,毕竟题目中合法涂色是不可能出现 0 的。

时间复杂度:O(nlog2n)

参考代码:

#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 2e5 + 100;struct SegmentTree { //写成结构体的形式方便操作    struct Tnode {        int l, r;        int lch, rch;        int val;        Tnode () { lch = rch = val = 0; }    } tree[maxn << 2];    int freePoint;    SegmentTree () { freePoint = 0; }    int getPoint(int l, int r) { //动态分配法,更灵活,避免造成浪费        int root = ++freePoint;        tree[root].l = l;        tree[root].r = r;        return root;    }    int build(int l, int r) {        int root = getPoint(l, r);        if (l < r) {            int mid = (l + r) >> 1;            tree[root].lch = build(l, mid);            tree[root].rch = build(mid + 1, r);        }        return root;    }    void pushDown(int root) { //打散        if (tree[root].val) {            tree[tree[root].lch].val = tree[root].val;            tree[tree[root].rch].val = tree[root].val;            tree[root].val = 0;        }    }    void update(int l, int r, int color, int root) {        Tnode& node = tree[root];        if (node.r < l || r < node.l) return;        if (l <= node.l && node.r <= r) {            tree[root].val = color;            return;        }        pushDown(root);        update(l, r, color, node.lch);        update(l, r, color, node.rch);    }    int queryOne(int pos, int root) {        Tnode& node = tree[root];        if (node.l == pos && node.r == pos) return node.val;        pushDown(root);        if (pos <= tree[node.lch].r) return queryOne(pos, node.lch); else return queryOne(pos, node.rch);    }} SegT;int n, m;int main(void) {    freopen("1833.in", "r", stdin);    freopen("1833.out", "w", stdout);    scanf("%d%d", &n, &m);    int root = SegT.build(1, n);    for (int i = 0; i < m; i++) {        int order;        scanf("%d", &order);        if (order == 1) {            int a, b, c;            scanf("%d%d%d", &a, &b, &c);            SegT.update(a, b, c, root);        }        if (order == 2) {            int x;            scanf("%d", &x);            printf("%d\n", SegT.queryOne(x, root));        }    }    return 0;}


0 0
原创粉丝点击