您的位置:首页 > 其它

POJ 2777 Count Color

2014-07-20 21:07 155 查看
题目大意:

现只有一个测例, 一个长度为L的长板,总共由L个相同的小段组成(1 ≤ L ≤ 100,000),小段从左到右编号为1 ~ L,现在给长板上色,规定每个小段只能涂一种颜色,刚开始时全部都涂成颜色1,假设总共有T中颜色(1 ≤ T ≤ 30),现在有O个操作(1 ≤ O ≤ 100,000),操作共有两种,一种是"C A B C",表示给编号区间[A, B]上颜色C(颜色用1 ~ T的整数表示),另一种操作是"P A B",表示要求你输出区间[A, B]之中不同颜色的总数。

题目链接

注释代码:

/*
* Problem ID : POJ 2777 Count Color
* Author     : Lirx.t.Una
* Language   : C
* Run Time   : 250 ms
* Run Memory : 840 KB
*/

#include <stdio.h>

//板的最大长度
#define	MAXN		100000

#define	LFT(T)		( (T) << 1 )
#define	RHT(T)		( LFT(T) | 1 )

//将颜色数值转换成二进制表示方式
//颜色n就表示成二进制数第n位为1的形式
#define	COLOR(C)	( 1 << ( (C) - 1 ) )
//判断一个颜色是否为纯色,纯色就只有1位有1,混色多位有1
//即检查C的二进制数是否只含一个1
#define	SINGL(C)	( !( ( (C) - 1 ) & (C) ) )

//线段树,保存区间中颜色的二进制表示形式
//如果一个区间结点的颜色为0011,而其区间为[1, 5],
//则表示该区间中有两种颜色,一种是颜色1,另一种是颜色2
int		seg[MAXN * 3] = { 0, 1 };//根结点下标为1,因此将结点1区间都涂成颜色1

void
update( int tree, int c, int ul, int ur, int lft, int rht ) {
//tree结点[lft, rht]中奖区间[ul, ur]颜色涂成二进制颜色c

int		mid;
int		tl, tr;//tree_lft and tree_rht
int		tpc;//tmp_color,临时二进制颜色变量

//上的颜色肯定是纯色的
//如果当前结点区间已经是纯色而且和要上的色一样
//那就相当于啥事儿都没干
if ( c == seg[tree] ) return ;

if ( lft == ul && ur == rht ) {//命中后区间直接上色,不呀再向下分解

seg[tree] = c;
return ;
}

tl  = LFT(tree);
tr  = RHT(tree);
mid = ( lft + rht ) >> 1;
tpc = seg[tree];

//未命中,因为命中的时候直接上色了,子结点不管情况如何都不管了,因此
//纯色结点的子结点不一定能正确反映父结点的信息,所以必须往下带
if ( SINGL(tpc) ) {//如果当前区间是纯色,需要将颜色往下带(分解)

seg[tl] = tpc;
seg= tpc;
}

if ( ur <= mid )
update( tl, c, ul, ur, lft, mid );
else if ( ul > mid )
update( tr, c, ul, ur, mid + 1, rht );
else {

update( tl, c, ul, mid, lft, mid );
update( tr, c, mid + 1, ur, mid + 1, rht );
}

//跟新父结点的颜色,就是两个子结点按位或,将所有颜色都集中
seg[tree] = seg[tl] | seg;
}

int
query( int tree, int ql, int qr, int lft, int rht ) {

int		mid;

//如果当前结点区间(大区间)[lft, rht]已经是纯色的了则直接return不必再继续分解
//先检查纯色再检查是否命中可以省更多时间
if ( SINGL( seg[tree] ) || lft == ql && qr == rht ) return seg[tree];

mid = ( lft + rht ) >> 1;

if ( qr <= mid ) return query( LFT(tree), ql, qr, lft, mid );
else if ( ql > mid ) return query( RHT(tree), ql, qr, mid + 1, rht );
else return query( LFT(tree), ql, mid, lft, mid ) |
query( RHT(tree), mid + 1, qr, mid + 1, rht );
}

int
main() {

int		n, t, q;//板长,颜色数,询问数
int		lft, rht, c;//c接受临时颜色(1 ~ t之间的整数)

int		tmp;//临时变量
int		i;//计数变量
char	cmd;

int		ans;//询问区间的不同颜色数量

scanf("%d%d%d", &n, &t, &q);

while ( q-- ) {

scanf("\n%c%d%d", &cmd, &lft, &rht);
if ( lft > rht ) {//对于左端点大于右端点的交换端点

tmp = lft;
lft = rht;
rht = tmp;
}

switch (cmd) {

case 'C' :

scanf("%d",&c);
update( 1, COLOR(c), lft, rht, 1, n );

break;

case 'P' :

ans = 0;
c   = query( 1, lft, rht, 1, n );

for ( i = 0; i < t; i++ )//统计二进制数中1的个数
ans += 1 & ( c >> i );
printf("%d\n", ans);

break;

default : break;
}
}

return 0;
}
无注释代码:

#include <stdio.h>

#define	MAXN		100000

#define	LFT(T)		( (T) << 1 )
#define	RHT(T)		( LFT(T) | 1 )
#define	COLOR(C)	( 1 << ( (C) - 1 ) )
#define	SINGL(C)	( !( ( (C) - 1 ) & (C) ) )

int		seg[MAXN * 3] = { 0, 1 };

void
update( int tree, int c, int ul, int ur, int lft, int rht ) {

int		mid;
int		tl, tr;
int		tpc;

if ( c == seg[tree] ) return ;

if ( lft == ul && ur == rht ) {

seg[tree] = c;
return ;
}

tl  = LFT(tree);
tr  = RHT(tree);
mid = ( lft + rht ) >> 1;
tpc = seg[tree];

if ( SINGL(tpc) ) {

seg[tl] = tpc;
seg= tpc;
}

if ( ur <= mid )
update( tl, c, ul, ur, lft, mid );
else if ( ul > mid )
update( tr, c, ul, ur, mid + 1, rht );
else {

update( tl, c, ul, mid, lft, mid );
update( tr, c, mid + 1, ur, mid + 1, rht );
}

seg[tree] = seg[tl] | seg;
}

int
query( int tree, int ql, int qr, int lft, int rht ) {

int		mid;

if ( SINGL( seg[tree] ) || lft == ql && qr == rht ) return seg[tree];

mid = ( lft + rht ) >> 1;

if ( qr <= mid ) return query( LFT(tree), ql, qr, lft, mid );
else if ( ql > mid ) return query( RHT(tree), ql, qr, mid + 1, rht );
else return query( LFT(tree), ql, mid, lft, mid ) |
query( RHT(tree), mid + 1, qr, mid + 1, rht );
}

int
main() {

int		n, t, q;
int		lft, rht, c;

int		tmp;
int		i;
char	cmd;

int		ans;

scanf("%d%d%d", &n, &t, &q);

while ( q-- ) {

scanf("\n%c%d%d", &cmd, &lft, &rht);
if ( lft > rht ) {

tmp = lft;
lft = rht;
rht = tmp;
}

switch (cmd) {

case 'C' :

scanf("%d",&c);
update( 1, COLOR(c), lft, rht, 1, n );

break;

case 'P' :

ans = 0;
c   = query( 1, lft, rht, 1, n );

for ( i = 0; i < t; i++ )
ans += 1 & ( c >> i );
printf("%d\n", ans);

break;

default : break;
}
}

return 0;
}
单词解释:

optional:adj, 可选的,选修的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: