W同学的新画板 QDUOJ 线段树 区间颜色段数
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 线段树 区间颜色段数的更多相关文章
- SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)
题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和 分析 : 一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序 ...
- HYSBZ - 2243 树链剖分 + 线段树 处理树上颜色段数
用线段树处理颜色段数 记录区间内的颜色段数,区间右端点的颜色,区间右端点的颜色. int tr[maxn<<2], lc[maxn<<2], rc[maxn<<2] ...
- 【APIO2018】新家(线段树)
[APIO2018]新家(线段树) 题面 UOJ 洛谷 BZOJ 题解 论比赛时想不到二分的危害,就只能Cu滚粗 既然不要在线,那么考虑离线做法. 既然时间是区间,那么显然按照时间顺序处理答案. 显然 ...
- 计蒜客 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 ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- hihoCoder 1080 : 更为复杂的买卖房屋姿势 线段树区间更新
#1080 : 更为复杂的买卖房屋姿势 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho都是游戏迷,“模拟都市”是他们非常喜欢的一个游戏,在这个游戏里面他们 ...
- HDU 5023 A Corrupt Mayor's Performance Art(线段树区间更新)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色 ...
- I Hate It(hdu1754)(线段树区间最大值)
I Hate It hdu1754 Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 线段树(区间合并) POJ 3667 Hotel
题目传送门 /* 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 输入 2 a b:将[a,a+b-1]的房间清空 线段树(区间合并):lsum[]统计从左端点起最长连续空房间 ...
随机推荐
- MySQL——Alias
查询时,当表名很长或者执行一些特殊查询的时候,为了方便操作或者需要多次使用相同的表时,可以为表指定别名,用这个别名代替表原来的名称. 设置别名为表设置别名 <表名> [AS] <别名 ...
- JAVA中的23种设计模式
http://blog.csdn.net/chmask/article/details/2631485 http://www.cnblogs.com/hnrainll/archive/2011/12/ ...
- ubuntu中查看AMD GPU 状态的办法
lshw -c video 运行命令:glxinfo | grep rendering 如果结果是“yes”,证明显卡驱动已经成功安装. 如果提示有问题,可能是系统里面没有安装mesa-utils,安 ...
- Redis实战(十三)Redis的三种集群方式
序言 能聊聊redis cluster集群模式的原理吗 资料 https://www.cnblogs.com/51life/p/10233340.html Redis 集群分片原理
- luogu P1314 聪明的质监员 x
P1314 聪明的质监员(至于为什么选择这个题目,可能是我觉得比较好玩呗) 题目描述 小T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有 n 个矿石,从 1到n 逐一编号,每个矿石都有自 ...
- CSV文件在Python中的几种处理方式
Comma Separated Values,简称CSV,它是一种以逗号分隔数值的文件类型.在数据库或电子表格中,它是最常见的导入导出格式,它以一种简单而明了的方式存储和共享数据,CSV文件通常以纯文 ...
- Android如何安装系统应用,及自己增加安装系统应用的接口
根据SIM卡安装系统应用 功能: 1:如何安装系统应用,apk放在system/app系统分区下面. 2:根据SIM卡的归属国家选择性的安装应用. 一:本人使用方法: 在开机的服务里面添加接口(Pac ...
- C# walls
在学习C#的阶段中,我们一点一点的往前爬, 此代码需要添加selenium ,和 获取 引用. using Ivony.Html.Parser; using Ivony.Html; using Ope ...
- sql中left join、right join、inner join的区别
转自https://www.cnblogs.com/pcjim/articles/799302.html left join.right join.inner join区别 left join(左联 ...
- linux服务器在线测速
cd /tmpwget https://raw.github.com/sivel/speedtest-cli/master/speedtest.py或者wget https://raw.githubu ...