ZOJ 1610 Count the Colors

Count the Colors

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones.

Your task is counting the segments of different colors you can see at last.


Input

The first line of each data set contains exactly one integer n, 1 <= n <= 8000, equal to the number of colored segments.

Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:

x1 x2 c

x1 and x2 indicate the left endpoint and right endpoint of the segment, c indicates the color of the segment.

All the numbers are in the range [0, 8000], and they are all integers.

Input may contain several data set, process to the end of file.


Output

Each line of the output should contain a color index that can be seen from the top, following the count of the segments of this color, they should be printed according to the color index.

If some color can't be seen, you shouldn't print it.

Print a blank line after every dataset.


Sample Input

5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1


Sample Output

1 1
2 1
3 1

1 1

0 2
1 1

 

昨天看POJ上的提交记录,已经整整三个月没有做过题了,真是堕落啊。。。

今天复习线段树,写了这个染色问题。

重点就是加入一个bool变量做为标志,这样在更新和查询的时候都不用一直查到叶子结点,这样大大提高效率。

思路在代码中有详细注释

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 
  5 using namespace std;
  6 
  7 typedef struct
  8 {
  9     int left,right;
 10     int color;
 11     bool End;
 12 } NODE;
 13 
 14 typedef struct
 15 {
 16     int left,right;
 17     int color;
 18 }SEGMENT;
 19 
 20 int t;
 21 int color[10000];
 22 NODE node[40000];
 23 SEGMENT segment[10000];
 24 
 25 //对线段树进行初始化
 26 void initial(int root,int l,int r)
 27 {
 28     node[root].left=l;
 29     node[root].right=r;
 30     if(l<r-1)
 31     {
 32         initial(root*2+1,l,(l+r)/2);
 33         initial(root*2+2,(l+r)/2,r);
 34     }
 35 }
 36 
 37 //对线段树进行染树,root为根节点,l和r为染色范围,color为染的颜色
 38 void paint(int root,int l,int r,int color)
 39 {
 40     //如果染色范围与根节点没有交集,则直接返回
 41     if(l>=node[root].right||r<=node[root].left)
 42         return ;
 43 
 44     //如果根节点的范围被染色范围完全包围,则将根节点染色并将此结点标记为true(即查询时到这里为止)
 45     if(l<=node[root].left&&r>=node[root].right)
 46     {
 47         node[root].color=color;
 48         node[root].End=true;
 49     }
 50     else  //根节点的范围与染色范围只胡部分交集时
 51     {
 52         //若根节点之前标记为true,则先将根节点的颜色递归地染到它的子树上去,然后将根节点改为false
 53         if(node[root].End)
 54         {
 55             paint(root*2+1,node[root].left,(node[root].left+node[root].right)/2,node[root].color);
 56             paint(root*2+2,(node[root].left+node[root].right)/2,node[root].right,node[root].color);
 57             node[root].End=false;
 58         }
 59         //如果根节点的范围与染色范围只在左儿子部分重合,则只需递归地染色左孩子
 60         if(r<=(node[root].left+node[root].right)/2)
 61             paint(root*2+1,l,r,color);
 62         //如果根节点的范围与染色范围只在右儿子部分重合,则只需递归地染色右孩子
 63         else if(l>=(node[root].left+node[root].right)/2)
 64             paint(root*2+2,l,r,color);
 65         //如果染色范围与左右孩子都有重合,则需要递归地染色左右孩子
 66         else
 67         {
 68             paint(root*2+1,l,(node[root].left+node[root].right)/2,color);
 69             paint(root*2+2,(node[root].left+node[root].right)/2,r,color);
 70         }
 71     }
 72 }
 73 
 74 //查询函数,root为要查询的根节点
 75 void dfs(int root)
 76 {
 77     //如果根节点的End为false则还要递归地查询它的左右孩子
 78     if(!node[root].End)
 79     {
 80         dfs(root*2+1);
 81         dfs(root*2+2);
 82     }
 83     //如果根节点的End为true则可以停止递归并记录下这次染色
 84     else
 85     {
 86         if(node[root].color!=-1)
 87         {
 88             segment[t].left=node[root].left;
 89             segment[t].right=node[root].right;
 90             segment[t].color=node[root].color;
 91             t++;
 92         }
 93     }
 94 }
 95 
 96 int main()
 97 {
 98     int n;
 99 
100     //建立线段树
101     initial(0,0,8000);
102 
103     while(scanf("%d",&n)==1)
104     {
105         //初始化线段树的根节点,最初没有染过色,所以根节点End=true,颜色color=-1表示没有染色
106         node[0].End=true;
107         node[0].color=-1;
108 
109         int x1,x2,c;
110 
111         //读入数据并染色
112         for(int i=1;i<=n;i++)
113         {
114             scanf("%d %d %d",&x1,&x2,&c);
115             paint(0,x1,x2,c);
116         }
117 
118         t=0;
119 
120         //查询每段的染色状况
121         dfs(0);
122 
123         //处理查询结果,合并相邻且相同颜色的线段,求出共有多少条线段
124         for(int i=0;i<10000;i++)
125             color[i]=0;
126         color[segment[0].color]=1;
127 
128         for(int i=1;i<t;i++)
129         {
130             if(segment[i].color==segment[i-1].color&&segment[i].left==segment[i-1].right)
131                 continue;
132             color[segment[i].color]++;
133         }
134 
135         //输出结果
136         for(int i=0;i<10000;i++)
137             if(color[i])
138                 printf("%d %d\n",i,color[i]);
139 
140         printf("\n");
141     }
142 
143     return 0;
144 }
[C++]

 

posted @ 2013-12-04 19:16  ~~Snail~~  阅读(220)  评论(0编辑  收藏  举报