【数据结构】线段树

来源:互联网 发布:百度关键词挖掘软件 编辑:程序博客网 时间:2024/06/05 02:33
    啦啦啦啦啦啦线段树是个好东西- -
    好吧并没有什么好的- -但貌似还是很好啊- -
    线段树就是一棵树!
    顾名思义(又是这个词),就是求关于一段的某些什么什么东西。比如区间最大值啊什么的。

引用百科知识:

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

线段树至少支持下列操作:

Insert(t,x):将包含在区间 int 的元素 x 插入到树t中;

Delete(t,x):从线段树 t 中删除元素 x;

Search(t,x):返回一个指向树 t 中元素 x 的指针。

恩就是这样,我来画个图说明存储的数据吧:
【数据结构】线段树 - 李kuandui - 神殇KD灬度阡陌
    差不多是这个样子的。

    明显的,假设我们建立一棵线段树,它的时间复杂度的o(n),修改一个或是查询一个都是o(nlogn)
    为嘛?不为嘛!

    怎么求呢?拿修改来说,主要是运用递归的思想,一路往下找,找到要求的位置,修改值,再一路向上修改最大值什么的。

    而查找一个最大值呢?就是在找包含关系。

    如有8个数,求第2到第7的最大值:
    在1~8找2~7——>在1~4找2~7——>在1~2找2~7——>在2找2~7(发现2包含在2~7内,返回2的值)——>在3~4找2~7(发现3~4包含在2~7内,返回3~4的值)——>在5~8找2~7——>在5~6找2~7(······)——>在7~8找2~7——>在7找2~7

    就是这样(好累)。
    在找的过程中发现,因为区间是连续的,所以一段要么是完全被包含,要么是分叉继续找,而若是分叉部分完全被包含,则被包含的区域是连在一起的,不存在像【取了1~2、5~6而其他不去】的情况。
【数据结构】线段树 - 李kuandui - 神殇KD灬度阡陌
    如上图,黑色部分表示被包含。而我们可以看出,相对于左子树,其被包含部分都在右边;而相对于右子树,其被包含部分都在左边。

    讲了这么多,程序就直接放上去吧(CXB)

#include <iostream>using namespace std;const int maxN =1000007;const int oo = 0x0fffffff;struct Tnode{int l, r;int max;int lc, rc;};Tnode f[maxN];int fp=0;int root;int getPoint(int l, int r, int max){fp++;f[fp].l = l;f[fp].r = r;f[fp].max = max;return fp;}//存数据 int create(int l, int r){int now = getPoint(l,r,-oo); if (l<r) {f[now].lc =create(l, (l+r)/2);f[now].rc= create((l+r)/2+1, r);}return now;}//建立一棵线段树 void update(int root , int p, int x){int l = f[root].l;int r = f[root].r;if ( p<l || r<p ) return ;if (l==r) { f[root].max=x; return; }//找到要修改的点,进行修改 update(f[root].lc, p, x);//往左边找要修改的值 update(f[root].rc, p, x);//往右边找要修改的值 f[root].max = max ( f [ f[root].lc ].max, f [ f[root].rc ].max );//修改当前节点最大值 }//修改第p个数据 int query(int root,int l,int r){if (l==f[root].l && r==f[root].r) return f[root].max;int mid = (f[root].l+f[root].r) / 2;int ans = -oo;if (l <= mid) ans = max(ans,query(f[root].lc,l,min(mid,r)));//查找左边最大值 if (r >= mid+1) ans = max(ans,query(f[root].rc,max(mid+1,l),r));//查找右边最大值 return ans;}//查询一段的最大值 int n;int q;int main(){cin >> n;root = create(1,n);cin >> q;char oper;int l,r,p,v;for (int i=0;i<q;++i){cin >> oper;if (oper == 'F')//找一段的最大值 {cin >> l >> r;cout << query(root,l,r) << endl;}elseif (oper == 'I')//修改一个值 {cin >> p >> v;update(root,p,v);}}return 0;}

 
0 0
原创粉丝点击