感谢兴海同学的耐心解释。
今天把线段树的创建,更新(插入),查找操作熟悉了。以前其实看过类似的资料,不过那时候脑子一片浆糊= =。。
想画图来着,感觉太不给力了。
直接说得了。
一、建图
我感觉,线段树的建图有两种。
1、最后一层建成线段,就是所有区间都是开区间,最后一层是[1,2] [2,3] [3,4]什么的。
2、最后一层建成点,类似[1,1] [2,2]..
今天建了下,个人比较喜欢第一种建法~感觉正好就是线段嘛。
建树我用的数组模拟邻接表,本来是想用指针的,不过感觉挺麻烦的,如果用指针的话就不能用位运算了哈。建树很简单,线段树是递归定义的,所以建树也是递归就好。
树的左右孩子直接由数组下标去寻找,左孩子是2*x,右孩子是2*x+1
#define L(x) x << 1
#define R(x) x << 1 | 1
根据题目的不同,树的结点可以增加其他的值去标记一些东西。比如我今天过的两个题,是标记颜色值,或者是否覆盖的。
void Build(int t,int l,int r)
{
node[t].cover = 0;
node[t].l = l;
node[t].r = r;
if( l == r-1 ) return ;
int mid = (l+r)>>1;
Build(L(t), l, mid);
Build(R(t), mid, r);
}
二、更新(我更喜欢叫更新是Updata。。。虽然准确的说应该是Update。。。)
1、注意更新父节点对子节点的影响。
2、注意更新子节点对父节点的影响。
3、开始我一直拿初始的l 和 r去更新,根本没用用到mid。后来问兴海,他说有的时候会有用。想了下,如果跟覆盖的区间有关的话,应该还是得用到,不过这两题都没用到 = =。。
4、如果父节点已经被覆盖过的话,如果这个父节点的子节点需要覆盖其他的颜色的话,父节点的颜色需要往子节点传递,才能保证这个线段不被多个颜色覆盖。传递后,这个父节点颜色就没有了,标记成-1。
void Updata(int t,int l,int r,int col)
{
if( r <= l ) return ;
if( l <= node[t].l && node[t].r <= r )
{
node[t].cover = col;
return ;
}
int mid = (node[t].l + node[t].r) >> 1;
if( node[t].cover > 0 )
{
node[R(t)].cover = node[t].cover;
node[L(t)].cover = node[t].cover;
node[t].cover = -1;
}
if( l >= mid )
Updata( R(t), l, r, col);
else
if( r <= mid )
Updata( L(t), l, r, col);
else
{
Updata( L(t), l, mid, col);
Updata( R(t), mid, r, col);
}
}
(剩下的见下一篇吧,睡觉去,明早得早起)