最近是一脸懵逼的集训时间
好吧,其实学的也蛮多的:搜索(bfs,dfs),
图论(包括了边表,邻接表,邻接矩阵,传递闭包,三角形迭代,floyed,Bellman-Ford,spfa,Dijkstra,Prim,Kurskal),
基本数论(gcd,lcm,费马小定理,线性筛法,欧拉函数,同余方程),
树状数组,
差分,差分约束,
线段树,
KMP算法,LCA,
dp(对拍,背包问题),AC自动机,Manachar算法,左偏树等等。(有背景色的内容在本文有简述)
学的多,忘得也多,所以不得不写篇blog纪念一下。
(好吧其实是咱老师要咱写)
/*--------------------------------------第一章:立志要种出一片森林的小孩-------------------------------------------*/
学完线段树之后,看到一大长串的代码就头大,知道大概五六天前,为了学LCA不得不重新拾起这一被本人抛弃的数据结构(To be honnest 本人在哪之前连模板题都懒得敲)。没想到一敲便上了瘾。
从云里雾里到有那么一丁点的感觉,还是走得有那么一点艰辛的,也花了很大的力气搞懂了几个傻不啦叽的问题:
1.线段树是什么:说简单点,他就是一颗二叉树,其root节点的左儿子的下标可看成root*2,右儿子则为root*2+1,对应的,root节点的父节点就可以表示为root/2(向下整取)。
2.线段树存的到底是什么:直到在lougu上敲模板题的时候才开始思考这个问题:线段树存的是一个区间的数值之和,尽管那个区间内可能只有一个元素。
3.线段树可以干什么:在我的印象中,线段树就是一种对区间问题有奇效的数据结构。
4.lazy标记到底是干什么的:lazy标记就像当于一个区间加减的印记,可以帮助我们减少递归的次数并且在必须的时候顺便把数值传递到下一个区间。
本人对线段树的理解目前就这么浅尝辄止,有待进一步的开发与升级。
线段树代码镇帖:
种树:
void build(int root,int l,int r)
{
int mid=l+r>>1;
if (l==r) {
tree[root].zhi=read();return;}
build(root<<1,l,mid);
build((root<<1)+1,mid+1,r);
tree[root].zhi=tree[root<<1].zhi+tree[root<<1|1].zhi;
}
区间修改:
void growl(int root,int l,int r)
{
if(k2<l||k1>r)
return;
if(k1<=l&&k2>=r)
{tree[root].add++;tree[root].lazy++;return;}
int mid=(l+r)/2;
int delta=tree[root].lazy;
tree[root*2].lazy+=delta;
tree[root*2].add+=delta;
tree[root*2+1].add+=delta;
tree[root*2+1].lazy+=delta;
tree[root].lazy=0;
growl(root*2,l,mid);
growl(root*2+1,mid+1,r);
tree[root].add=max(tree[root*2].add,tree[root*2+1].add);
}
区间查询:
int find(int root,int l,int r)
{
if(k2<l||k1>r)
return -1;
if(k1<=l&&k2>=r)
return tree[root].add;
int mid=(l+r)/2;
int delta=tree[root].lazy;
tree[root*2].lazy+=delta;
tree[root*2].add+=delta;
tree[root*2+1].add+=delta;
tree[root*2+1].lazy+=delta;
tree[root].lazy=0;
return max(find(root*2,l,mid),find(root*2+1,mid+1