Count Color(线段树)

题目链接:2777 -- Count Color

翻译:有一个很长的板子,长L厘米,L是一个正整数,所以我们可以把板子平均分成L段,从左到右用1,2,...L标记,每段1厘米长。现在我们必须给棋盘上色——只有一种颜色的一段。我们可以在棋盘上做以下两种操作:

1. "CAB C" 将棋盘从 A 段到 B段涂上颜色 C。 

2. "PA B" 输出 A 段和 B 段之间绘制的不同颜色的数量。

分析:我们可以把一个区间存在的颜色用一个数的二进制来表示,其实这个很简单,比如某一段区间的颜色是9,其对应的二进制为1001,这就意味着这段区间上存在2种颜色,也就是说某段区间的颜色种数就是这段区间颜色值的二进制表示中1的个数,至于pushup操作,就是当前区间的两个子区间的或值,然后剩下的就是一个线段树模板了。下面直接上代码了:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=1e6+10;
int sum[N],l[N],r[N],lazy[N];
//返回x中1的个数 
int lowbit(int x)
{
	int cnt=0;
	while(x)
	{
		cnt++;
		x-=x&-x;
	}
	return cnt;
}
//用二进制表示颜色,用或求区间颜色总数 
void pushup(int id)
{
	sum[id]=sum[id<<1]|sum[id<<1|1];
}
void pushdown(int id)
{
	if(lazy[id])
	{
		lazy[id<<1]=lazy[id];
		lazy[id<<1|1]=lazy[id];
		sum[id<<1]=lazy[id];
		sum[id<<1|1]=lazy[id];
		lazy[id]=0;
	}
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;sum[id]=1;lazy[id]=0;
	if(L==R) return ;
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
	pushup(id);
}
void update_interval(int id,int L,int R,int val)
{
	if(l[id]>R||r[id]<L) return ;
	if(l[id]>=L&&r[id]<=R)
	{
		sum[id]=val;
		lazy[id]=val;
		return ;
	}
	pushdown(id);
	update_interval(id<<1,L,R,val);
	update_interval(id<<1|1,L,R,val);
	pushup(id);
}
int query_interval(int id,int L,int R)
{
	if(l[id]>R||r[id]<L) return 0;
	if(l[id]>=L&&r[id]<=R) return sum[id];
	pushdown(id);
	return query_interval(id<<1,L,R)|query_interval(id<<1|1,L,R);
}

int main()
{
	int n,t,q;
	cin>>n>>t>>q;
	build(1,1,n);
	char op[20];
	int x,y,z;
	while(q--)
	{
		scanf("%s",op);
		//x和y相对大小不确定,坑死我了 
		if(op[0]=='C')
		{
			scanf("%d%d%d",&x,&y,&z);
			update_interval(1,min(x,y),max(x,y),1<<z-1);
		}
		else
			{
				scanf("%d%d",&x,&y);
				printf("%d\n",lowbit(query_interval(1,min(x,y),max(x,y))));
			}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值