这题很明显,就是要实现两种操作:区间修改和单点查询,是典型的数据结构裸题,可以用线段树解决。
因为题目没有太多好讲的,我们不妨先回顾一下线段树这个数据结构,最后再稍来点拨一下本题。
首先还是要回到本质,数据结构到底是什么?为什么 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;
}