原文地址:http://blog.csdn.net/zxy_snow/article/details/6636162
&& http://blog.csdn.net/zxy_snow/article/details/6676302
一、建图
我感觉,线段树的建图有两种。
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);
}
}
大致分为这几类
操作:
1、区间覆盖,染色啊,异或啊,加上一个数,乘一个数,都变成某个数啊神马的。
2、涉及矩形的一些方法。
3、区间单值更新。
4、类似二分的查找位置。
5、类似约瑟夫环的一些东东。
6、。。。。
询问:
1、区间最值,第K值。
2、区间和,各种和。
3、区间连续区域的位置,连续区域最大长度。
4、和DP一起,区间最长XX子序列神马的。
5、。。。。
目前见过的就这几种吧,其实看起来蛮少的。恶心的是好几种操作,好几种询问混到一道题上,想shi。。
而且写线段树特别需要头脑清楚,因为设计好线段树的域很重要,而且需要想清楚各种更新,稍不留神就挂了。
能用函数写尽量用函数,要不写着写着会晕的。
LAZY标记是个很强大也很讨厌的东东 T T 。。。它省了好多时间,不过更新细节需要狠狠注意。
二维线段树我只会用树套树解决很水的问题,什么四分树不会,见的题不多。
合适的节点设计会省事很多,我越来越懒了 = =。。struct里加了好几个函数。
我的一维线段树的定义。不过就纠结的是,不能使用名字为len的变量了 = =。。
struct Tnode{
int l,r,val;
long long sum;
int len() { return r - l;}
int mid() { return MID(l,r);}
bool in(int ll,int rr) { return l >= ll && r <= rr; }
void lr(int ll,int rr){ l = ll; r = rr;}
};
二维的,基本和一维函数都差不多。struct T2node
{
int l,r;
Tnode son[MAXM<<2];
int len() { return r - l;}
int mid() { return MID(l,r);}
bool in(int ll,int rr) { return l >= ll && r <= rr; }
void lr(int ll,int rr){ l = ll; r = rr;}
};