POJ 2777 (线段树)

//关键点:
//1. 用位代表颜色,计算某个段的颜色组成时,用或运算:
//   line[c].color = line[c<<1].color | line[(c<<1)+1].color
//2. 延时着色,即当某一层为纯色时,则将它的子节点都标记为该颜色
#include <iostream>
using namespace std;

struct node{
	int from, to;
	//每一位代表一种color,而且有如下关系式
	//line[c].color = line[c<<1].color | line[(c<<1)+1].color
	int color;
};

const int MAX_NUM = 100002;
node line[3*MAX_NUM];

//建树
void build_tree(int from, int to, int c)
{
	line[c].from = from;
	line[c].to = to;
	line[c].color = 1;
	if (from == to) return;
	int mid = (from + to) / 2;
	build_tree(from, mid, c<<1);
	build_tree(mid+1, to, (c<<1)+1);
}

int paint(int from, int to, int color, int c)
{
	//使用了延时着色,因为
	//如果是if (line[c].from == line[c].to)则超时
	if (line[c].from == from && line[c].to == to){
		line[c].color = color;
	}
	else {
		//延时着色,即当某一层为纯色时,则将它的子节点都标记为该颜色
		if (((line[c].color) & (line[c].color-1)) == 0){
			line[c<<1].color = line[(c<<1)+1].color = line[c].color;
		}
		int mid = line[c<<1].to;
		if (from > mid){
			line[c].color = line[c<<1].color 
				| paint(from, to, color, (c<<1)+1);
		}
		else{
			if (to > mid){
				line[c].color = paint(from, mid, color, c<<1) 
					| paint(mid+1, to, color, (c<<1)+1);
			}
			else{
				line[c].color = paint(from, to, color, c<<1) 
					| line[(c<<1)+1].color;
			}
		}
	}
	return line[c].color;
}

int query (int from, int to, int c)
{
	if (line[c].from == from && line[c].to == to){
		return line[c].color;
	}
	if (((line[c].color) & (line[c].color-1)) == 0){ //延时着色
		line[c<<1].color = line[(c<<1)+1].color = line[c].color;
	}
	int mid = line[c<<1].to;
	if (from > mid){
		return query(from, to, (c<<1)+1);
	}
	else{
		if (to > mid){
			return query(from, mid, c<<1) | query(mid+1, to, (c<<1)+1);
		}
		else{
			return query(from, to, c<<1);
		}
	}
}

inline void swap(int& a, int &b)
{
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
}

int main()
{
	int L, T, O, i, A, B, C, cnt;
	char opt;
	scanf("%d%d%d", &L, &T, &O);
	build_tree(1, L, 1);
	for (i = 0; i < O; ++i){
		cin>>opt;
		if (opt == 'C'){
			scanf("%d%d%d", &A, &B, &C);
			if (A > B) swap(A, B);
			paint(A, B, 1<<(C-1), 1);
		}
		else{
			scanf("%d%d", &A, &B);
			if (A > B) swap(A, B);
			C = query(A, B, 1);
			cnt = 0;
			while (C){
				cnt++;
				C &= (C-1);
			}
			printf("%d\n", cnt);
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值