以上为ZOJ-1610原题。
题意为:已知一条线段,给定一个数字n,代表n次涂色;三个数字x1,x2,c,分别代表被涂色线段的左端点,右端点和颜色号。
——最坑的地方在0-8000的设定。建树时不能拿n建树,要拿8000建树;线段长度要设为8001;颜色块数组长度要设为8001。//这也是我出错的点
求:线段上有颜色的对应颜色段的个数,如果没有这个颜色,不予列出;如果有这个颜色,求出现这个颜色段的个数。
#include <iostream>
#include <cstdio>
using namespace std;
struct Node
{
int l;
int r;
}Line[800000];
int n;
int color[8001] = {0};
int line[8001] = {-1};
void build(int k,int l,int r)//建树
{
Line[k].l = l;
Line[k].r = r;
if(l==r)
{
line[l]=-1;
return;
}
int mid = (l+r)/2;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
void rebuild(int k)//重建树,主要是把line[]上的颜色清空;
{
if(Line[k].l == Line[k].r){
line[Line[k].l] = -1;
return;
}
rebuild(k*2);
rebuild(k*2+1);
}
void paint(int k,int x1,int x2,int c)//线段涂色
{
if(Line[k].l==Line[k].r){
line[Line[k].l] = c;
return;
}
int mid = (Line[k].l+Line[k].r)/2;
if(x2<=mid)
paint(k*2,x1,x2,c);
else if(x1>mid)
paint(k*2+1,x1,x2,c);
else{
paint(k*2,x1,mid,c);
paint(k*2+1,mid+1,x2,c);
}
}
void get()//涂色后统计各颜色段个数
{
for(int i = 1;i <= 8000; i++)
{
if(line[i]!=-1&&(i==1||line[i]!=line[i-1]))
color[line[i]]++;
}
}
void number()//输出各颜色段个数
{
for(int i = 0;i <= 8000; i++)
{
if(color[i]>0){
printf("%d %d\n",i,color[i]);
}
color[i]= 0;
}
}
int main()
{
int x1,x2,c;
build(1,1,8000);
while(~scanf("%d",&n)){
for(int i = 0;i < n; i++){
scanf("%d%d%d",&x1,&x2,&c);
paint(1,x1+1,x2,c);
}
get();
number();
rebuild(1);
printf("\n");
}
return 0;
}