题型:线段树
描述:跟长为L的木棒的[a,b]段涂颜色,问[a1,b1]区间的不同颜色数。
思路:线段树的区间修改,“父节点控制子节点的思想”,当left = t[k].left && right = t[k].right 时更改 color域,并返回,不再修改其子节点的color值。
color = 0 表示当前区间有多种颜色,如果 [left, right]没有完全覆盖当前区间,则 t[2*k].color = t[2*k+1].color = t[k].color; t[k].color = 0; 即,
将子节点的颜色值改为父节点的颜色值,父节点的颜色值置为 0 。
心得:
1.刚开始写的很不熟练,错误百出,后参考了笑风生的博客,发现很喜欢其代码风格,于是学习了一下。
2.关于数组开多大,令NL 取 大于L 的 2^k数。
// key 1第一次都写成了 [left, mid]或 [mid, right]
// key 2为关键之处,借鉴于笑风生
// 4244K 344MS
#include < stdio.h >
#include < string .h >
#define SWP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
#define NL 131072
struct Seg {
int l, r, md;
int clr;
}t[NL * 2 ];
bool flg[ 31 ];
int cnt;
void build( int l, int r, int k)
{
t[k].l = l;
t[k].r = r;
t[k].md = (l + r) / 2 ;
if (l + 1 < r) {
build(l, t[k].md, k * 2 );
build(t[k].md, r, k * 2 + 1 );
}
}
void mody( int l, int r, int k, int clr)
{
if (t[k].l == l && t[k].r == r) {
t[k].clr = clr;
return ;
}
if (t[k].clr > 0 ) { // key 2
t[ 2 * k].clr = t[ 2 * k + 1 ].clr = t[k].clr;
t[k].clr = 0 ;
}
if (r <= t[k].md) mody(l, r, k * 2 , clr); // key 1
else if (l >= t[k].md) mody(l, r, k * 2 + 1 , clr); // key 1
else {
mody(l, t[k].md, k * 2 , clr);
mody(t[k].md, r, k * 2 + 1 , clr);
}
}
void count( int l, int r, int k) {
if (t[k].clr) { // key 2
flg[t[k].clr] = 1 ;
return ;
}
if (r <= t[k].md)
count(l, r, k * 2 ); // key 1
else if (l >= t[k].md)
count(l, r, k * 2 + 1 ); // key 1
else {
count(l, t[k].md, k * 2 );
count(t[k].md, r, k * 2 + 1 );
}
}
int main()
{
int L, T, O, i, j;
int a, b, c, tmp;
char s[ 3 ];
while (scanf( " %d%d%d " , & L, & T, & O) != EOF) {
build( 1 , L + 1 , 1 );
t[ 1 ].clr = 1 ;
for (i = 0 ; i < O; i ++ ) {
scanf( " %s " , s);
if (s[ 0 ] == ' C ' ) {
scanf( " %d%d%d " , & a, & b, & c);
if (a > b) SWP(a,b,tmp);
mody(a, b + 1 , 1 , c);
} else {
scanf( " %d%d " , & a, & b);
if (a > b) SWP(a,b,tmp);
memset(flg, 0 , sizeof (flg));
cnt = 0 ;
count(a, b + 1 , 1 );
for (j = 1 ; j <= T; j ++ ) {
if (flg[j]) cnt ++ ;
}
printf( " %d\n " , cnt);
}
}
}
return 0 ;
}