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 ",i,color[i]); 139 140 printf(" "); 141 } 142 143 return 0; 144 }