线段树有两种建树方案:
1.单点
区间【1,5】,分为【1,3】【4,5】->【1,2】【3】【4】【5】(各区间边界
都不相邻,每个边界即是一个点)
PS: 如果存的是线段,要将线段用单点的形式表示,比如【1,2】区间,将左 端点+1,变成2这个点,就可以用单点这种形式的线段树。
处理方式build(l,mid); build(mid+1,r);
2.线段
正常理解即可。但建树时终止条件为l==r-1,表明一个单位区间。
处理方式,build(l,mid); build(mid,r);
例题:Count the Colors ZOJ - 1610 (线段树,区间覆盖求染色段个数)
1.单点代码:
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e4+7;
struct node
{
int l,r,type;
} tree[maxn<<2];
int a[maxn];
int n,m;
void build(int x,int l,int r)
{
tree[x].type=-1;
tree[x].l=l,tree[x].r=r;
if(l==r)
return ;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void pushdown(int x)
{
if(tree[x].type!=-1)
tree[x<<1].type=tree[x<<1|1].type=tree[x].type,tree[x].type=-1;
}
void update(int x,int L,int R,int c)
{
if(L<=tree[x].l&&R>=tree[x].r)
{
tree[x].type=c;
return ;
}
if(tree[x].l==tree[x].r)return ;
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(L<=mid)update(x<<1,L,R,c);
if(R>mid)update(x<<1|1,L,R,c);
}
void query(int x)
{
if(tree[x].l==tree[x].r)
{
if(tree[x].type!=m&&tree[x].type!=-1)
a[tree[x].type]++;
m=tree[x].type;
return ;
}
pushdown(x);
query(x<<1);
query(x<<1|1);
}
int main()
{
int i,j,x,y,c;
while(~scanf("%d",&n))
{
m=-1;
memset(a,0,sizeof(a));
build(1,1,8000);
for(i=1; i<=n; i++)
{
scanf("%d%d%d",&x,&y,&c);
if(x<y)update(1,x+1,y,c);
}
query(1);
for(i=0; i<8000; i++)
{
if(a[i])
printf("%d %d\n",i,a[i]);
}
printf("\n");
}
return 0;
}
2.区间代码:
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1e4+7;
struct node
{
int l,r,type;
} tree[maxn<<2];
int a[maxn];
int n,m;
void build(int x,int l,int r)
{
tree[x].type=-1;
tree[x].l=l,tree[x].r=r;
if(l==r-1)
return ;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid,r);
}
void pushdown(int x)
{
if(tree[x].type!=-1)
tree[x<<1].type=tree[x<<1|1].type=tree[x].type,tree[x].type=-1;
}
void update(int x,int L,int R,int c)
{
if(L<=tree[x].l&&R>=tree[x].r)
{
tree[x].type=c;
return ;
}
if(tree[x].l==tree[x].r-1)return ;//重点,保证合法,因为区间建树不存在
//左右节点相等的节点,所以要把这种情况排除
pushdown(x); //细节案例为0——1区间,mid=0,但不存
//在左右节点都为0的节点(L=0,mid=0)
int mid=(tree[x].l+tree[x].r)>>1;
if(L<=mid)update(x<<1,L,R,c);
if(R>mid)update(x<<1|1,L,R,c);//R=mid也可以
}
void query(int x)
{
if(tree[x].l==tree[x].r-1)
{
if(tree[x].type!=m&&tree[x].type!=-1)
a[tree[x].type]++;
m=tree[x].type;
return ;
}
pushdown(x);
query(x<<1);
query(x<<1|1);
}
int main()
{
int i,j,x,y,c;
while(~scanf("%d",&n))
{
m=-1;
memset(a,0,sizeof(a));
build(1,0,8000);
for(i=1; i<=n; i++)
{
scanf("%d%d%d",&x,&y,&c);
update(1,x,y,c);
}
query(1);
for(i=0; i<=8000; i++)
{
if(a[i])
printf("%d %d\n",i,a[i]);
}
printf("\n");
}
return 0;
}