线段树进阶-染色问题 附poj-2777题解

区域染色覆盖问题

        假设某大学有一面文化墙,各个学院都可以在上面涂色,要求涂色区域高必须和墙一样,宽度任意但必须是整数(以米为单位)。涂色可以覆盖其他学院的涂色。现在若干个学院涂色之后最终这面墙上能看见多少种颜色。

        这就是简单的染色问题了。当然有很多种不同的说法,但整体上离不开这两个问题:1.区域覆盖。2.多种染色方式。既然是区域操作,那么用线段树是比较合理了。用数组也可以,但是数据规模稍微大一点就会TLE。

        当然,跟染色问题一同存在的还有就是离散化,很多博客也是将这两者一起来写的,并且主要是离散化。但我个人感觉染色问题对理解线段树很有帮助(当然还是太菜了= =大佬们都认为难点是线段树的离散化),所以就单独拿出来了。

建树

        线段树有多种表现形式,感觉很多人都是拿结构体写的,博主是用数组写的,其本质还是一样的代码有些不一样而已。

        整体上,我们对一段数据建成线段树,那么区域染色的时候就类似与修改区间。而线段树的精髓就是利用lazy数组,可以保证不遍历到子结点就可以获得区域的情况。那么染色也要利用这个性质,对于一段区间,我们想要在上层结点上来表示出来。那么我们可以设置3个变量:-1 表示当前区段有多种颜色,具体有多少种不用管。0表示当前区域未染色。正整数表示当前区域染了单一染色,并且颜色号是这个正整数。

        所以除了特殊要求,一般我们用int来表示颜色种类(就算题目是char类型或者string,我们也可以变成int,最多写一个hash,还是整数方便)。那么看下面这个例子:

        这是按照上面的要求写的线段树,-1表示当前段有多种颜色,1表示当前段全部是1。这里左边,一个1一个0,而上面结点仍然是-1。这是因为默认把0也当成一种颜色了,可以节省代码,实际在查找的时候我们只用排除0就可以得到正确答案。

        总之,这样建立的线段树可以表示区域染色的大致情况。而具体有多少种颜色需要在查询的时候进行操作。

        关于建树,因为染色问题,所以有覆盖这种说法,后涂的颜色会覆盖先涂的,所以一般原数据是什么都没有,也就是整个线段树的值全是0。这样初始化代码只用将线段树初始化就行了。即:

void build(){
    memset(tree,0,sizeof(tree));
}
// 有这样的情况,底层有规定颜色,那么就不能用memset而是要用for循环
void build(int color){
    for(int i = 1;i <= len;i++){
        tree[i] = color;
    }
}

不排除有刚开始就有涂色的

  • 22
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值