题目地址:http://acm.pku.edu.cn/JudgeOnline/problem?id=2528

 因为实现的线段树的元线段是一个左闭右开区间,题目中输入的线段需要做一下处理,我通过将右端点加1,就可以和线段树对应了。

 接下来是离散化,去重点。

线段树中增加一个color域,初始值为0,-1表示当前点表示的线段有多个颜色,大于0表示单一颜色。

插入线段时先判断插入线段颜色是否和当前线段相同,不同则插入,

如果完全覆盖当前线段,把color域设置为插入线段颜色,并return.否则把其左右儿子color设置为当前节点color,把当前节点color设置为-1.

递归插入。

在统计的时候 只要统计到一个节点color域大于0就把标志数组的第color设为true,并返回,不用再继续递归统计下去,因为其子节点都被覆盖。

最后遍历标记数组统计为true的个数,即颜色数。

代码
#include <iostream>
#include 
<cstring>
#include 
<cstdio>
#include 
<algorithm>
using namespace std;
const int MAXN = 20010;
struct line
{
    
int l;
    
int r;
};
line a[MAXN];
struct node
{
    
int l;
    
int r;
    
int mid;
    
int color;
};
node seg_tree[MAXN
*4];
bool flag[MAXN];
int hash[MAXN*2];
void make(int l,int r,int num)
{
    seg_tree[num].l 
= l;
    seg_tree[num].r 
= r;
    seg_tree[num].mid 
= (l+r)/2;
    seg_tree[num].color 
= 0;
    
if (l+1!=r)
    {
         make(l,seg_tree[num].mid,num
*2);
         make(seg_tree[num].mid,r,num
*2+1);
         
return;
    }
}
void insert(int num,int l,int r,int c)
{
   
// printf("test\n");
    if (seg_tree[num].color!=c)
    {
        
if (seg_tree[num].l==l&&seg_tree[num].r==r)
        {
            seg_tree[num].color 
= c;
            
return;
        }
        
if (seg_tree[num].color>=0)
        {
            seg_tree[
2*num].color = seg_tree[num].color;
            seg_tree[
2*num+1].color = seg_tree[num].color;
            seg_tree[num].color 
= -1;
        }
        
if(r<=seg_tree[num].mid)
        {
            insert(
2*num,l,r,c);
        }
        
else if(l>=seg_tree[num].mid)
        {
            insert(
2*num+1,l,r,c);
        }
        
else
        {
            insert(
2*num,l,seg_tree[num].mid,c);
            insert(
2*num+1,seg_tree[num].mid,r,c);
        }
    }
}
void cal(int num)
{
    
if(seg_tree[num].color>0)
    {
        flag[seg_tree[num].color] 
= true;
        
return;
    }
    
if(seg_tree[num].l+1!=seg_tree[num].r)
    {
        cal(
2*num);
        cal(
2*num+1);
    }
}
inline 
int b_search(int l,int r,int val)
{
    
while(l<=r)
    {
        
int mid = (l+r)>>1;
        
if(hash[mid]==val)return mid;
        
else if(hash[mid]>val)r=mid-1;
        
else l = mid +1;
    }
    
return -1;
}
int main()
{
    
int T,n;
    scanf(
"%d",&T);
    
while (T--)
    {
        memset(flag,
false,sizeof(flag));
        scanf(
"%d",&n);
        
for (int i=1;i<=n;i++)
        {
            scanf(
"%d%d",&a[i].l,&a[i].r);
            a[i].r
++;
            hash[
2*i-1= a[i].l;
            hash[
2*i] = a[i].r;
        }
        sort(hash
+1,hash+1+2*n);
        
int index = 2;
        
for(int i=1;i<2*n;i++)
        {
            
if(hash[i]!=hash[i+1])
            {
                hash[index
++= hash[i+1];
            }
        }
        make(
1,index-1,1);

        
for(int i=1;i<=n;i++)
        {
           
// printf("test a %d b %d\n",b_search(1,index-1,a[i].l),b_search(1,index-1,a[i].r));
            insert(1,b_search(1,index-1,a[i].l),b_search(1,index-1,a[i].r),i);
        }
         cal(
1);
        
int ans = 0;
        
for(int i=0;i<MAXN;i++)
        {
            
if(flag[i])
            {
                
//printf("c %d\n",i);
                ans++;
            }
        }
        printf(
"%d\n",ans);

    }
    
return 0;
}