PKU 2777

PKU 2777

题型:线段树

描述:跟长为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;
}

 

 

posted @ 2010-07-16 12:02  superbin  阅读(379)  评论(0编辑  收藏  举报