W同学的新画板 QDUOJ 线段树 区间颜色段数

原题链接

题意

W同学在每天的刻苦学习完成功课之余,都会去找一些有趣的事情来放松自己;恰巧今天他收到了朋友送给他的一套画板,于是他立刻拆开了包装,拿出其中的画板和一些画笔,开心地画了起来;这时W同学注意到了闲暇的你正好待在一旁,于是他灵机一动,打算考验一下你的眼力,具体过程是这样的:

W同学收到的画板可看作一个长条状的木板,画板从左端到右端可划分为等长的连续的n段(自左至右依次编号为第1段,第2段,第3段,...,第n段,如下图所示),开始时每一段都有一个初始的颜色,之后W同学会进行一些操作,每次操作中他都会选一段区间[L,R],然后用画笔把画板的第L段~第R段这一块连续的部分染为颜色C(被染色的某段先前已存在的颜色会被新颜色覆盖),而且每当进行一些染色操作后,W同学都有可能会让你立即答出他给你的某段区间[L,R]中共有多少个颜色段,以此考察你的眼力,聪明的你敢不敢接受W同学的考验?

解题思路

使用线段树来进行处理这个题是大体的思路,原因在于题目要求一段区间内的颜色段数。要注意的是,这里是求取一段区间内的颜色的段数,不是有多少种颜色,比如 1 2 2 1 1 这个画板就有3段颜色,和自己以前做的求取区间内的颜色的种类数不同,这个题目还没想过,确实很新,参考的CH大佬的代码,下方链接。

参考大佬的思路

代码实现(带注释)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5e5+7;
struct Node{
int l, r;
int sum, lazy;//sum记录这里有几段颜色段,lazy就是线段树常用的标记
int le, re; //这里是来记录这段区间的左右端点处的颜色种类
}node[maxn<<2];
int col[maxn]; //存储初始的颜色种类
void up(int rt)
{
node[rt].sum=node[rt<<1].sum+node[rt<<1|1].sum; //左右区间段数相加
if(node[rt<<1].re==node[rt<<1|1].le)//这里需要注意左右段的交界处,如果相等的话,总的段数是要进行减一的
node[rt].sum--; //这里想一想是不是
node[rt].le=node[rt<<1].le;
node[rt].re=node[rt<<1|1].re;
}
void build(int rt, int l, int r)
{
node[rt].l=l;
node[rt].r=r;
node[rt].lazy=-1;
if(l==r)
{
node[rt].sum=1;
node[rt].le=node[rt].re=col[l];
return ;
}
int mid=(l+r)>>1;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
up(rt);
}
void down(int rt)
{
node[rt<<1].lazy=node[rt<<1|1].lazy=node[rt].lazy;
node[rt<<1].sum=node[rt<<1|1].sum=1; //左右的段数都归为1
node[rt<<1].le=node[rt<<1].re=node[rt].lazy;
node[rt<<1|1].le=node[rt<<1|1].re=node[rt].lazy; node[rt].lazy=-1;
}
void update(int rt, int l, int r, int v)
{
if(l <= node[rt].l && node[rt].r <= r)
{
node[rt].lazy = node[rt].le = node[rt].re = v;
node[rt].sum=1;
return ;
}
int mid=(node[rt].l+node[rt].r)>>1;
if(node[rt].lazy!=-1) //这里有点不一样
down(rt);
if(l<=mid) update(rt<<1, l, r, v);
if(r>mid) update(rt<<1|1, l, r, v);
up(rt);
}
int query(int rt, int l, int r)
{
if(l <= node[rt].l && node[rt].r <=r)
{
return node[rt].sum;
}
if(node[rt].lazy!=-1)
down(rt);
int ans=0, mid=(node[rt].l + node[rt].r)>>1;
//这里因为交界处的特殊性,所以询问的方式不再是if(l<=mid)……然后if(r>mid)……
//这里需要判断三种情况
//1.全部在左区间 2.全部在右区间 3.左右区间都有
//这里1,2种情况比较好处理,就是第3种情况需要特殊一些
//第三种情况也是分开两半来计算的,但是需要判断中间交汇处是不是需要进行减一
if(r<=mid) return query(rt<<1, l, r); //第一种情况
else if(l>mid) return query(rt<<1|1, l, r); //第二种情况
else ans=query(rt<<1, l, r)+query(rt<<1|1, l, r); //第三种情况,也是比较特殊的一种情况
if(node[rt<<1].re == node[rt<<1|1].le)//这是关键,判断中间交汇处的颜色是不是相等,相等需要减一
ans--;
return ans;
}
int main()
{
int n, q, op, a, b, c;
cin>>n>>q;
for(int i=1; i<=n; i++)
cin>>col[i];
build(1, 1, n);
for(int i=1; i<=q; i++)
{
cin>>op;
if(op==1)
{
cin>>a>>b>>c;
update(1, a, b, c);
}
else if(op==2)
{
cin>>a>>b;
cout<<query(1, a, b)<<endl;
}
}
return 0;
}

W同学的新画板 QDUOJ 线段树 区间颜色段数的更多相关文章

  1. SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)

    题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和 分析 : 一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序 ...

  2. HYSBZ - 2243 树链剖分 + 线段树 处理树上颜色段数

    用线段树处理颜色段数 记录区间内的颜色段数,区间右端点的颜色,区间右端点的颜色. int tr[maxn<<2], lc[maxn<<2], rc[maxn<<2] ...

  3. 【APIO2018】新家(线段树)

    [APIO2018]新家(线段树) 题面 UOJ 洛谷 BZOJ 题解 论比赛时想不到二分的危害,就只能Cu滚粗 既然不要在线,那么考虑离线做法. 既然时间是区间,那么显然按照时间顺序处理答案. 显然 ...

  4. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  5. POJ 3667 Hotel(线段树 区间合并)

    Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...

  6. hihoCoder 1080 : 更为复杂的买卖房屋姿势 线段树区间更新

    #1080 : 更为复杂的买卖房屋姿势 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho都是游戏迷,“模拟都市”是他们非常喜欢的一个游戏,在这个游戏里面他们 ...

  7. HDU 5023 A Corrupt Mayor's Performance Art(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色 ...

  8. I Hate It(hdu1754)(线段树区间最大值)

    I Hate It hdu1754 Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  9. 线段树(区间合并) POJ 3667 Hotel

    题目传送门 /* 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 输入 2 a b:将[a,a+b-1]的房间清空 线段树(区间合并):lsum[]统计从左端点起最长连续空房间 ...

随机推荐

  1. 1.关于python 的hmac加密

    import base64 import hmac import urllib from hashlib import sha1 expires = b" # 过期时间戳 uuid = 'a ...

  2. z-tree的使用

    1.参考资料 1)官网:http://www.treejs.cn/v3/api.php 2)z-tree码云:https://gitee.com/zTree/zTree_v3 2.下载解压 案例演示: ...

  3. JUnit——单元测试步骤

    步骤: 1. New Package(一般命名为*.Test,测试类与开发类放在不同的包中)2. New JUnit Text Case(一般命名为*Test)3. 选择需要测试的方法 4. 可以下载 ...

  4. CQOI2010 传送带

    题目链接:戳我 分别枚举线段AB上的出发点,和线段CD上的到达点,然后时间直接计算,取min就可以了. 但是这样子显然会T飞,(相当于1e5的平方吧?)所以我们进一步考虑性质. 然后打表(或者感性理解 ...

  5. cpp 实现简易String类

    需求 实现一个String类 自己写的String headers/String.h #ifndef __MYSTRING__ #define __MYSTRING__ #include <st ...

  6. Spring 4.2.2以上版本和swagger集成方案和踩过的坑

    因为公司使用的spring版本太高,在集成swagger的时候会存在一些问题,而网上的很多实例大多都是版本比较低的,为了是朋友们少才坑,我这边将集成的过程记录一下: 1. 引入spring.swagg ...

  7. Oracle rac11g 安装报INS41112

    由于集群服务器上的数据库存储层要上双活,所以需要重置存储 不幸17服务器在重启后突然奔溃了,所以需要重新安装17服务器系统 在把18的软件全都卸载干净后,重新安装集群服务器,但却遇到了如下问题 多次针 ...

  8. pwd命令学习

    pwd命令学习 1.学习pwd命令 pwd命令功能为输出当前所在工作目录的绝对路径名称. 绝对路径和相对路径: 绝对路径:从根目录开始直到文件位置 相对路径:相对于程序当前所在目录到文件位置 例:程序 ...

  9. File类 ReadAllBytes() ReadAllLines() ReadAllText()

    用 File 类里的 ReadAllLines方法读取文件string[] contents = File.ReadAllLines(@"F:\Users\zhuotu003\Desktop ...

  10. LibUsbDotNet使用方法

    最近在用C#调试USB程序,libusb源码是C语言的,C#用起来不方便,偶然在网上看到了LibUsbDotNet,这是开源的项目,下载后参考Example,用起来非常方便. LibUsbDotNet ...