题目大意:
现只有一个测例, 一个长度为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[tr] = 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[tr];
}
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[tr] = 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[tr];
}
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, 可选的,选修的