Count the Colors (ZOJ_1610) 线段树 + 线段统计

来源:互联网 发布:网络市场调研的含义 编辑:程序博客网 时间:2024/05/16 15:30
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


题目大意:给出若干区间及区间涂色序号,新涂色可覆盖旧涂色,求最后有多少各颜色有多少段。


解题思路:利用线段树区间更新,最后统计各颜色的区间段。

注意:1.给出的是区间的端点,线段树节点代表的是线段。2.区间查询,设flag代表上一涂色颜色,flag与tree[x].c相同时color[tree[x].c]++,否则,表示仍为同一颜色。3.当查询到达叶子节点时,flag必须改变,以为该线段可能未被涂色。


代码如下:

#include"iostream"#include"cstdio"#define maxn 10000using namespace std;struct _tree{int l,r,c;int getmid(){return (l+r)>>1;}}tree[maxn*20];struct _option{int l,r,c;}x[maxn*4]; int color[maxn];int flag;//纪录上一段区间的颜色 void pushdown(int x){int tmp=x<<1;tree[tmp].c=tree[x].c;tree[tmp+1].c=tree[x].c;tree[x].c=-1;}void Build(int l,int r,int x){tree[x].l=l;tree[x].r=r;tree[x].c=-1;if(l==r) return ;int tmp=x<<1;int mid=tree[x].getmid();Build(l,mid,tmp);Build(mid+1,r,tmp+1);}void Updata(int l,int r,int c,int x){if(l<=tree[x].l&&tree[x].r<=r){tree[x].c=c;return ;}if(l>tree[x].r||r<tree[x].l){return ;}if(tree[x].c!=-1){pushdown(x);}int tmp=x<<1;Updata(l,r,c,tmp);Updata(l,r,c,tmp+1);}void Query(int l,int r,int x){if(tree[x].c!=-1){if(flag!=tree[x].c){//区间查询,设flag代表上一涂色颜色,flag与tree[x].c相同时color[tree[x].c]++,否则,表示仍为同一颜色color[tree[x].c]++;//printf("[%d,%d]\n",tree[x].l,tree[x].r);flag=tree[x].c;}return ;}if(l==r){//当查询到达叶子节点时,flag必须改变,以为该线段可能未被涂色。flag=tree[x].c;return;} int mid=tree[x].getmid();int tmp=x<<1;Query(l,mid,tmp);Query(mid+1,r,tmp+1);}int main(){int n;while(scanf("%d",&n)!=EOF){int i,nn=0,k=0;for(i=1;i<=n;i++){//给出的是区间的端点,线段树节点代表的是线段scanf("%d%d%d",&x[i].l,&x[i].r,&x[i].c);nn=x[i].r>nn?x[i].r:nn;//纪录最大值,确定板块数目 k=x[i].c>k?x[i].c:k;}Build(1,nn,1);for(i=1;i<=n;i++){if(x[i].l==x[i].r) continue;Updata(x[i].l+1,x[i].r,x[i].c,1);}for(i=0;i<=nn;i++){color[i]=0;}flag=-1;Query(1,nn,1);for(i=0;i<=k;i++){if(color[i]!=0) printf("%d %d\n",i,color[i]);}printf("\n");}return 0;}





0 0
原创粉丝点击