问题:在X轴上的覆盖n条各种颜色(可以相同)一定长度的线段,问X轴被分成多少个段?
分析: 定义cover如下:cover=-1表示该区间由多种颜色组成。cover>=0表示该区间只有一种单一的颜色cover。
插入算法:
void insert(int i, int l, int r, int color) //将区间[l,r]的颜色改为color
{
int mid;
if (tree[i].cover == color) return; //如果结点i的颜色已经是color,返回,这句可不要
if (tree[i].b == l && tree[i].e == r) //如果区间和结点重合,则直接染色
tree[i].cover = color;
else
{
mid = (tree[i].b+tree[i].e)/2;
if (tree[i].cover >=0) //如果结点区间为单色
{
tree[i*2].cover = tree[i].cover; //颜色先传递给子结点,因为子结点以前未染色
tree[i*2+1].cover = tree[i].cover;
tree[i].cover = -1; //结点区间为杂色
}
if (r <= mid)
insert(2*i, l, r , color); //只在左子染色
else if (l >= mid)
insert(2*i+1, l, r, color); //只在右子染色
else //二分
{
insert(2*i, l, mid, color);
insert(2*i+1, mid, r, color);
}
}
}
统计算法:
int cnt(int i, int &lc, int &rc) //lc:左儿子颜色, rc:右儿子颜色
{
int ret, tl, tr, j, k;
if (tree[i].cover >= 0) //处理单一颜色
{
lc = tree[i].cover;
rc = tree[i].cover;
if (tree[i].cover > 0)
return 1;
else
return 0;
}
j = cnt(i*2, lc, tl); //把传入参数lc, rc作为递归参数进一步传递非常有用,它保证了lc, rc能取得离中点mid最近的单色区间的颜色值,以便后面判断是否需要-1
k = cnt(i*2+1, tr, rc);
ret = j+k;
if (tl == tr && tl > 0) //连接处颜色相同并且非底色,则总数减1
ret--;
return ret;
}
这个题在分析统计算法时,学生有疑问,然后我们一起研究,发现j = cnt(i*2, lc, tl)中的lc的作用很关键。作为引用型参数,它可以把递归调用中的里层实例的值带回本层,又会进一步把本层的值继续往外层传。于是,从本层的角度看,lc和rc实际了得到了离中间点mid最近的左右两个单色区间的颜色值。如果它们相等,则颜色区间个数要-1.