标签:
- 离散化
- 线段树
- 染色问题
思路:
- 很容易想到线段树的区间修改。具体怎么处理呢?我们给线段树的节点增加一个color属性,找到对应的区间给他染色。那么会出现几个问题。
-
假设一共有10个节点,加入对1-3区间染色,那么经过了的1-10区间如何处理?
我们将不能代表整个区间颜色的节点置为0。例如要对区间1-5染色,我们首先会经过1-10,然后递归来到1-5.这里我们只对1-5区间进行染色,而不对1-10进行染色操作。
-
同上10个节点,如果我先对1-10染色,再对1-5染色,怎么处理呢?
对1-10,我们可以直接覆盖,1-10的颜色修改为1。接下来对1-5染色,首先来到1-10的节点,我们先将1-10spread一下,使得1-5变为1,6-10也变为1,然后使1-10的颜色标记为不存在。再将1-5的颜色记为2.
-
按照上面的做法做完后怎么计算颜色呢?
颜色是覆盖的,每次涂色时,途径的节点都会改为真实颜色,所以最终我们直接单点查询所有的叶子节点,途径的节点都spread一下,保证查询到的是真实颜色。
-
注意事项:
- 询问只有2000个,而节点共有1e7个,因此我们考虑离散化。但是普通离散化会导致一个问题,例如对区间[1,4], [4,7], [7, 8]染色,离散化后[4,7]区间就没有颜色了!而[4-7]本身应该是有颜色的,归根结底,是因为[4,7]离散化成了[3,4]使得[3.4]之间没有节点。因此我们离散化时,不仅要知道他们的相对大小,还需要知道原数据是相邻还是相间的,如果相间的,我们不能离散化成相邻。所以我们直接对离散化集合扫一遍,遇到相间的,则在里面插入一个和端点相同的元素,保证离散化后,这两个数仍然相间。
AC代码
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 10000000 + 10;
const int maxm = 2000 + 10;
struct Node
{
int l, r;
int co;
};
Node tree[maxm * 4];
void build(int o, int l, int r)
{
tree[o].l = l, tree[o].r = r;
if (l == r)
return;
int mid = (l + r) / 2;
build(o * 2, l, mid);
build(o * 2 + 1, mid + 1, r);
}
void spread(int o)