算法题整理——线段树

POJ2777_Count Color

描述

有一块长度为L厘米的板子,我们可以把板子分成L块,每块一厘米长。

我们现在给板上色,规则是一块只能涂一种颜色,使用不同的整数取描述某种颜色,我们可以做的操作有:

“C A B C” 把区间[A,B]涂成颜色C。

“P A B” 输出区间[A,B]之间的不同颜色数。

在最开始时,整个板的颜色是1。

数据范围

板子长度 1 <= L <= 100000

颜色数 1 <= T <= 30

操作数 1 <= O <= 100000

思路

建立存储着区间内部各颜色种类的线段树,由于颜色数小于32,可以使用一个整形变量的每一位来存储这个区间内有没有这种颜色的点。

更新时,做按位或可以合并两个子节点的状态。

解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <cstdio>
#include <algorithm>

using namespace std;

const int L = 1e5 + 5;

struct node{
int left;
int right;
int lazy;
unsigned int color;
}t[L * 4];

int l, tt, o;

void update(int id){
t[id].color= (t[id << 1].color | t[id << 1 | 1].color);
}

void spread(int id){
if(t[id].lazy){
t[id << 1].color = t[id].color;
t[id << 1 | 1].color = t[id].color;
t[id << 1].lazy = t[id].lazy;
t[id << 1 | 1].lazy = t[id].lazy;
t[id].lazy = 0;
}
}

void create(int left, int right, int id){
t[id].left = left;
t[id].right = right;
t[id].lazy = 0;
if(left != right){
int mid = (left + right) >> 1;
create(left, mid, id << 1);
create(mid + 1, right, id << 1 | 1);
update(id);
}else{
t[id].color = 1;
}
}

void change(int left, int right, int color, int id){
if((t[id].left >= left) && (t[id].right <= right)){
t[id].color = (1 << (color - 1));
t[id].lazy = color;
}else{
spread(id);
int mid = (t[id].left + t[id].right) >> 1;
if(left <= mid){
change(left, right, color, id << 1);
}
if(right > mid){
change(left, right, color, id << 1 | 1);
}
update(id);
}
}

unsigned int query(int left, int right, int id){
if((t[id].left >= left) && (t[id].right <= right)){
return t[id].color;
}else{
spread(id);
int mid = (t[id].left + t[id].right) >> 1;
unsigned int ret = 0;
if(right > mid){
ret |= query(left, right, id << 1 | 1);
}
if(left <= mid){
ret |= query(left, right, id << 1);
}
return ret;
}
}

int trans(unsigned int ret){
int r = 0;
unsigned temp = 1;
for(int i = 0; i < 32; ++i){
r += (bool)(ret & temp);
temp <<= 1;
}
return r;
}

int main(){
scanf("%d %d %d\n", &l, &tt, &o);
create(1, l, 1);
int x, y, c;
char input[105];
while(o--){
gets(input);
if(input[0] == 'C'){
sscanf(input + 2, "%d %d %d", &x, &y, &c);
if(x > y)swap(x, y);
change(x, y, c, 1);
}else{
sscanf(input + 2, "%d %d", &x, &y);
if(x > y)swap(x, y);
printf("%d\n", trans(query(x, y, 1)));
}
}
return 0;
}