线段树学习

来源:互联网 发布:米兔机器人如何编程 编辑:程序博客网 时间:2024/05/16 05:33

原文地址: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);elseif( 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;}    };