POJ_2777_Count Color_线段树

今天做了三道线段树,感觉自己萌萌哒。


题意:

一个线段,分成l份,每个点涂一种颜色。可以区间修改,离线询问某些区间中有多少种颜色。

Input

First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains "C A B C" or "P A B" (here A, B, C are integers, and A may be larger than B) as an operation defined previously.

Output

Ouput results of the output operation in order, each line contains a number.


线段树的区间更新,用lazy思想,今天忘了在update那里判断是否需要释放标记,改了好久。。。。。。。

可以给线段树每个节点加数组记录第i种颜色是否存在,但是由于经常会进行赋值操作,显然用int+位运算更加划算。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxn 100010
int l,t,o;
int ll[mxn<<2],rr[mxn<<2],data[mxn<<2],flag[mxn<<2];
void build(int l,int r,int id){
	ll[id]=l;
	rr[id]=r;
	flag[id]=0;
	data[id]=1;
	if(l==r)	return;
	int m=(l+r)>>1,ls=id<<1,rs=ls|1;
	build(l,m,ls);
	build(m+1,r,rs);
}
void down(int id);
void update(int l,int r,int x,int id){
	if(ll[id]==l&&rr[id]==r){
		data[id]=1<<(x-1);
		flag[id]=x;
		return;
	}
	int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
	if(flag[id])	down(id);
	if(r<=m)	update(l,r,x,ls);
	else if(l>m)	update(l,r,x,rs);
	else{
		update(l,m,x,ls);
		update(m+1,r,x,rs);
	}
	data[id]=data[ls]|data[rs];
}
void down(int id){
	if(ll[id]==rr[id])	return;
	int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
	update(ll[id],m,flag[id],ls);
	update(m+1,rr[id],flag[id],rs);
	flag[id]=0;
}
int find(int l,int r,int id){
	if(ll[id]==l&&rr[id]==r)	return data[id];
	if(flag[id])
		down(id);
	int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
	if(r<=m)	return find(l,r,ls);
	else if(l>m)	return find(l,r,rs);
	else	return find(l,m,ls)|find(m+1,r,rs);
}
void swap(int& a,int& b){
	a=a+b;
	b=a-b;
	a=a-b;
}
int main(){
	scanf("%d%d%d",&l,&t,&o);
	build(1,l,1);
	char op;
	int a,b,c,ans,tem;
	for(int O=0;O<o;++O){
		ans=0;
		cin>>op;
		if(op=='C'){
			scanf("%d%d%d",&a,&b,&c);
			if(a>b)	swap(a,b);
			update(a,b,c,1);
		}
		else{
			scanf("%d%d",&a,&b);
			if(a>b)	swap(a,b);
			tem=find(a,b,1);
			for(int i=0;i<t;++i)	if(tem&(1<<i))
				++ans;
			printf("%d\n",ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值