W同学的新画板 - (区间合并)

题目链接:https://qduoj.com/problem/606

题目:

Description

 

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

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

无标题.png

Input

 

第一行包含两个整数n和q,分别表示木板的长度和操作的次数;(1 <= n,q <= 500000)

接下来一行中包含n个以空格隔开的整数 col1col_1col1​ ~ colncol_ncoln​,分别表示初始时每一段的颜色,0 <= colicol_icoli​ <= 10910^9109

接下来的q行,每行会给出如下两种操作的一种:

1 a b c :表示W同学此时将画板的第a段~第b段这部分区域染为颜色c(1 <= a <= b <= n,0 <= c <= 10910^9 109)

2 a b:表示此刻W同学询问你,画板的第a段~第b段这一部分中此时共有多少个颜色段(1 <= a <= b <= n)

Output

 

对于每次询问,输出相应的答案,每次询问的输出各占一行。

Sample Input 1

6 4 
1 2 2 3 3 1
2 2 5 
2 1 5
2 2 2 
2 1 6

Sample Output 1

2
3
1
4

Sample Input 2

5 5
0 0 0 0 0
1 1 2 1
1 4 5 1
2 1 2 
2 2 4 
2 1 5

Sample Output 2

1
3
3

Hint

对于样例一,初始时[1,6]区间中共有四段颜色:1 22 33 1;

对于样例二,初始时画板状态为00000,第一次操作后状态为11000,第二次操作后状态为11011,故[1,2]段中只有一个颜色段11,[2,4]中有三个颜色段1 0 1,[1,5]中有三个颜色段11 0 11。

 

解题思路:我做这个题时,将统计区间内有多少种颜色与区间内有多少个颜色段弄混了,做了好长时间也没做出来,思路也不清晰,后来看了一些类似题才懂,也有了清晰的思路。

具体见代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,q;
const int INF=5e5+5;
struct node{
	int left,right;
	int sum;//统计区间内有多少个颜色段
        int lazy;
	int le,re;
}f[4*INF];
int a[INF];
void pushup(int ans)
{
	f[ans].sum =f[ans<<1].sum +f[ans<<1|1].sum ;
	if(f[ans<<1].re ==f[ans<<1|1].le )//此时要减一,注意
	{
		f[ans].sum --;
	}
	f[ans].le =f[ans<<1].le ;
	f[ans].re =f[ans<<1|1].re ;
}
void build(int ans,int l,int r)
{
	f[ans].right =r;f[ans].left =l;
	f[ans].lazy =-1;
	if(l==r)
	{
		f[ans].sum =1;
		f[ans].le=f[ans].re =a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(ans<<1,l,mid);
	build(ans<<1|1,mid+1,r);
	pushup(ans);
}
void pushdown(int ans)
{
	f[ans<<1].sum =f[ans<<1|1].sum =1;
	f[ans<<1|1].le =f[ans<<1|1].re =f[ans].lazy ;
	f[ans<<1].re=f[ans<<1].le =f[ans].lazy ;
	f[ans<<1].lazy =f[ans<<1|1].lazy =f[ans].lazy ;
	f[ans].lazy =-1;
}
void update(int ans,int l,int r,int x)
{
	if(f[ans].left >=l&&f[ans].right <=r)
	{
		f[ans].sum =1;
		f[ans].le=f[ans].re =x;
		f[ans].lazy =x;
		return ;
	}
	if(f[ans].left !=f[ans].right &&f[ans].lazy !=-1)
	{
		pushdown(ans);
	}
	int mid=(f[ans].left +f[ans].right)>>1;
	if(l<=mid)update(ans<<1,l,r,x);
	if(r>mid)update(ans<<1|1,l,r,x);
	pushup(ans);
 } 
int getsum(int ans,int l,int r)
{
	if(f[ans].left ==l&&f[ans].right ==r)
	{
		return f[ans].sum ;
	}
	if(f[ans].left !=f[ans].right &&f[ans].lazy !=-1)	pushdown(ans);
	int mid=(f[ans].left +f[ans].right )>>1;
	int val;
	if(r<=mid)return getsum(ans<<1,l,r);
	else if(l>mid)return getsum(ans<<1|1,l,r);
	else val=getsum(ans<<1,l,mid)+getsum(ans<<1|1,mid+1,r);
	if(f[ans<<1].re ==f[ans<<1|1].le )val--;//注意这个情况,要减一
	return val;
}
int main()
{
	cin>>n>>q;
	int i,j,k,val;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	build(1,1,n);
	for(i=1;i<=q;i++)
	{
		int cn;
		scanf("%d",&cn);
		if(cn==1)
		{
			scanf("%d%d%d",&j,&k,&val);
			update(1,j,k,val);
		}
		else if(cn==2)
		{
			scanf("%d%d",&j,&k); 
			val=getsum(1,j,k);
			printf("%d\n",val);
		}
	}
    return 0;	
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值