POJ 2777 Count Color 暑假 —— 线段树1 ——H

Count Color
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 29895   Accepted: 8919

Description

Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. 

There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board: 

1. "C A B C" Color the board from segment A to segment B with color C. 
2. "P A B" Output the number of different colors painted between segment A and segment B (including). 

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your. 

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.

Sample Input

2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2

Sample Output

2
1
 
 
题意:有一块长度为l的木板,这个木板有l个长度为1的小木板组成(每个小木板初始颜色为t1)。现在有t种颜料,o个操作

操作共有2种: C L R V  :把木板第L块至R块木板的颜色换成V      P L R:求木板L块至R块有多少种不一样的颜色。 

思路:经典的线段树题(lazy标记)+按位或运算符('|')求不同颜色的数目

在"改段求段型"模板修改一下,每个结点维护4个值:区间左端点,区间又端点,区间的颜色(lazy),是否都被涂成一样的颜色

关于区间的颜色(lazy):因为t只有小于等于30,所以可以利用二进制的每一位表示一种颜色.

例如:颜色t种颜色:t1...tt   

则t1【2^(1-1)】: 0000 0001  t2【2^(2-1)】: 0000 0010  t3:【2^(3-1)】 0000 0100 ....
 
因为按位或是对应位置有1那么结果就为1,所以如果木板有颜色t1和t2,那么按位或之后就变成 0000 0011 
 
则不同的颜色数目就等于对应数字二进制1的个数.

 
 

//#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cmath>
#include <algorithm>
using namespace std;
typedef long long int LL;
#define R(k)(k<<1|1)
#define L(k)(k<<1)
#define INF 0x3f3f3f3f
const int MAXN = 100005;
const int MAXT = 31;
struct Node
{
	int l, r;//区间开始和结束
	int col;//用一个32位的int型,每一位对应一种颜色
	bool vis;//表示这个区间都被涂上同一种颜色。
};
Node tree[MAXN * 3];
int bit_one(int x)//求整数X转换成二进制后有多少个1
{
	int m = 0;
	while (x>0)
	{
		x = (x&(x - 1));
		m++;
	}
	return m;
}
void build(int s, int e, int k)
{
	if (s == e)
	{
		tree[k].l = s;
		tree[k].r = e;
		tree[k].col = 1;//注意题目要求每个格子初始颜色为1
		tree[k].vis = true;
		return;
	}
	int mid = (s + e) >> 1;
	tree[k].l = s;
	tree[k].r = e;
	tree[k].vis = true;
	build(s, mid, L(k));
	build(mid + 1, e, R(k));
	tree[k].col = tree[L(k)].col | tree[R(k)].col;
}
void pushup(int k)
{
	tree[k].col = tree[L(k)].col | tree[R(k)].col;
}
void pushdown(int k)
{
	if (tree[k].vis)
	{
		tree[L(k)].col = tree[k].col;
		tree[L(k)].vis = true;
		tree[R(k)].col = tree[k].col;
		tree[R(k)].vis = true;
		tree[k].vis = false;
	}
}
void updata(int s, int e, int k, int v)
{
	if (s==tree[k].l&&e==tree[k].r)
	{
		tree[k].vis = true;
		tree[k].col = 1<<(v-1);
		return;
	}
	pushdown(k);
	int mid = (tree[k].l + tree[k].r) >> 1;
	if (e <= mid)
	{
		updata(s, e, L(k), v);
	}
	else if (s > mid)
	{
		updata(s, e, R(k), v);
	}
	else
	{
		updata(s, mid, L(k), v);
		updata(mid + 1, e, R(k), v);
	}
	pushup(k);
}
int query(int s, int e, int k)//求不用颜色的数目
{
	if (s == tree[k].l&&e==tree[k].r)
	{
		return tree[k].col;
	}
	pushdown(k);
	int mid = (tree[k].l+tree[k].r) >> 1,num;
	if (e <= mid)
	{
		num=query(s, e, L(k));
	}
	else if (s > mid)
	{
		num=query(s, e, R(k));
	}
	else
	{
		num=query(s, mid, L(k)) | query(mid + 1, e, R(k));
	}
	pushup(k);
	return num;
}
int main()
{
	int l, t, o, a, b, c;
	char ch;
	scanf("%d %d %d", &l, &t, &o);
	build(1, l, 1);
	while (o--)
	{
		getchar();
		scanf("%c", &ch);
		if (ch == 'C')
		{
			scanf("%d %d %d", &a, &b, &c);
			updata(a, b, 1, c);
		}
		else
		{
			scanf("%d %d", &a, &b);
			printf("%d\n",bit_one(query(a, b, 1)));
		}
	}
	system("pause");
	return 0;
}

总结:巧妙运用二进制的每一位来表示一种状态,然后利用位运算符来求解答案。
 
 按位或:求解对应二进制中总的(两两不相等)状态数


你可能感兴趣的:(POJ 2777 Count Color 暑假 —— 线段树1 ——H)