要学会的是懒操作。这个题目跟北大的2777差不多,只是在计数的时候,有了变化。还有这个题目建树的时候需要注意一下。我建树建立错误,得到Segmentation Fault ,从来没遇到过这样的错误,现在长见识了。现在得好好总结一下这种线段树的做法了。类似于线段涂色的这种题目,建树要建立到元线段,而非点。更新的时候,要利用懒操作。没必要更新到叶子节点,主要是那样太浪费时间。如果更新父节点所在区间的一部分并且更新的时候同父节点原来保存的信息部哟样的话,需要先把父节点的信息传到孩子节点,对父节点进行特殊的标记,这样可以知道这个父节点所在区间保存的信息部唯一。这可能就是懒操作吧!感觉线段树有很多的变形,很灵活,要想很好的掌握,还得多练习啊!
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define N 8015
struct SegTree
{
int l,r,mid;
int col;
}tree[N*4];
int len[N],col[N];
void BuildTree(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
tree[root].mid=(l+r)>>1;
tree[root].col=-1;
if(l+1==r)return;
BuildTree(2*root,l,tree[root].mid);
BuildTree(2*root+1,tree[root].mid,r);
}
void Updata(int root,int l,int r,int c)
{
if(l<=tree[root].l&&tree[root].r<=r)
{
tree[root].col=c;
return;
}
if(tree[root].col==c)return;
if(tree[root].col>=0)
{
tree[2*root].col=tree[root].col;
tree[2*root+1].col=tree[root].col;
tree[root].col=-1; //将父节点置为-1,表明这个区间上不止一种颜色
}
if(r<=tree[root].mid)Updata(2*root,l,r,c);
else if(l>=tree[root].mid)Updata(2*root+1,l,r,c);
else
{
Updata(2*root,l,tree[root].mid,c);
Updata(2*root+1,tree[root].mid,r,c);
}
}
void count(int root,int l,int r)
{
if(tree[root].col>=0) //表明这个父节点所覆盖的区间只有一种颜色
{
for(int i=l;i<r;i++)
{
col[i]=tree[root].col;
}
return;
}
if(tree[root].l+1==tree[root].r)return ;
if(r<=tree[root].mid)count(2*root,l,r);
else if(l>=tree[root].mid)count(2*root+1,l,r);
else
{
count(2*root,l,tree[root].mid);
count(2*root+1,tree[root].mid,r);
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int t=n;
BuildTree(1,0,8000);
while(t--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Updata(1,a,b,c);
}
memset(col,-1,sizeof(col));
memset(len,0,sizeof(len));
count(1,0,8000);
for(int i=0;i<N;i++)
{
if(col[i+1]!=col[i]&&col[i]!=-1)
{
len[col[i]]++;
}
}
for(int i=0;i<N;i++)
{
if(len[i])printf("%d %d\n",i,len[i]);
}
printf("\n");
}
return 0;
}