poj 2777 Count Color

本文通过一道具体的题目,详细解析了如何使用线段树解决区间染色与查询问题。介绍了线段树的基本概念、实现细节及优化技巧。

        题意:一个长为L的板,分为L份。有两种操作,要么给一个区间着一种颜色(会覆盖掉以前的),要么询问一个区间颜色的种数。板的初始颜色为1,对于每个询问输出结果。

        思路:线段树。颜色用位来表示。因为总共不超过30种颜色,int足够了。第一种颜色对应二进制1,第二种颜色对应二进制10......对于每个段,设一个flag,如果是纯色,flag为true。lazy思想就是在不需要的时候,不去维护小段的颜色情况,每次只维护尽可能大的段。最后统计的时候递归按位或就行了。

        这是我的第一道线段树。。因为开空间不够大WA了一次。关于开空间我的理解是,树的形状可能是满二叉树的下面一层最左边和中间有叶子,得开三倍的空间。


#include <iostream>  
#include <stdio.h>  
#include <cmath>  
#include <algorithm>  
#include <iomanip>  
#include <cstdlib>  
#include <string>  
#include <memory.h>  
#include <vector>  
#include <queue>  
#include <stack>  
#include <map>
#include <set>
#include <ctype.h>  

#define INF 1000000

using namespace std;
//poj 2777
struct node{
	int l;
	int r;
	int color;
	bool flag;
};

node tree[300000];

void built(int n,int l,int r){
	tree[n].color=1;
	tree[n].l=l;
	tree[n].r=r;
	tree[n].flag=true;
	if(l!=r){
		int mid=(l+r)/2;
		built(n*2,l,mid);
		built(n*2+1,mid+1,r);
	}
}

void update(int n,int l,int r,int val){
	if(l==tree[n].l&&r==tree[n].r){
		tree[n].color=val;
		tree[n].flag=true;
		return;
	}
	
	int mid=(tree[n].l+tree[n].r)/2;
	if(tree[n].flag){
		update(n*2,tree[n].l,mid,tree[n].color);
		update(n*2+1,mid+1,tree[n].r,tree[n].color);
	}
	tree[n].flag=false;
	
	if(r<=mid){
		update(n*2,l,r,val);
	}else{
		if(l>=mid+1){
			update(n*2+1,l,r,val);
		}else{
			update(n*2,l,mid,val);
			update(n*2+1,mid+1,r,val);
		}
	}
}

int query(int n,int l,int r){
	if(tree[n].flag&&tree[n].l<=l&&tree[n].r>=r){
		return tree[n].color;
	}
	
	int mid=(tree[n].l+tree[n].r)/2;
	if(r<=mid){
		return query(n*2,l,r);
	}else{
		if(l>=mid+1){
			return query(n*2+1,l,r);
		}else{
			return query(n*2,l,mid)|query(n*2+1,mid+1,r);
		}
	}
}

int Cnt(int val){
	int re=0;
	while(val){
		if(val&1)re++;
		val>>=1;
	}
	return re;
}

int main(){
	int L;//长度 
	int T;//颜色数 
	int O;//操作数 
	
	while(cin>>L>>T>>O){
		built(1,1,L);
		while(O--){
			char oper;
			cin>>oper;
			if(oper=='C'){//更新 
				int A,B,C;
				scanf("%d%d%d",&A,&B,&C);if(B<A)swap(A,B);
				int col=1;
				col<<=(C-1);
				update(1,A,B,col);
			}
			if(oper=='P'){//查询 
				int A,B;
				scanf("%d%d",&A,&B);if(B<A)swap(A,B);
				printf("%d\n",Cnt(query(1,A,B)));
			}
		}
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值