周中记录--2017.9.7(线段树整理)

来源:互联网 发布:人工智能领域 编辑:程序博客网 时间:2024/06/05 03:08

开学第二周了。也终于逐渐稳定下来可以有条有序的处理问题了。首先说一点到现在为止的一点不足的地方,就是还没有去实验室学过习。这周末就要去做比赛了,周围都是大佬压力好大。。。

这周一直在忙的还有JAVA的学习,JAVA老师布置了很多很多的作业,虽然都是水题,但还是要认真完成。很多知识点感觉用到的需要上网去查,去学习。老师最新布置的题里,感觉。有些需要用搜索递归等去解决。写起来虽然和c++一样,但是vector,set等用法还是要去学习,这些和c++还是有区别的。虽然那些题可以暴力解决,没有给定数值范围,也没有时间限制,但是感觉如果用循环分分钟TLE。用算法解决还是要花一些时间的。但是也巩固了自己的知识点,也算是锻炼了自己。

再接下来的,就是研究了线段树的有关知识。下面写一下对线段树的理解总结。

线段树,有根节点和子节点还有父节点。它的本质就是一颗二叉树。线段树的每一个节点用于记录某一段区间上的信息。那么记录的是什么样的信息呢?线段树,首先是用来解决单点更新,区间查询,区间更新。那么线段树的每一个节点,储存的就是一段区间上的信息。对于任意一个非叶子节点,若该区间为[L,R],则左儿子节点为[L,(L+R)/2],右儿子节点为[(L + R)/2,R]。

线段树的实现:

#include <iostream>using namespace std;struct Tree{    int L,R;    int max,sum;};
用一个一维数组记录节点,且根节点的下标为1.那么对于任一节点a[k],其左儿子为a[2 * k],右儿子为a[2 * k + 1];

建立树也用到了类似递归的方式。源代码:


#include <iostream>using namespace std;struct Tree{    int L,R;    int max,sum;}tree[1000];int a[1000];void build(int id,int l,int r){    tree[id].L = l; tree[id].R = r;    if (l == r)    {        tree[id].sum = a[l];        tree[id].max = a[l];    }    else    {        int mid = (l+r)/2;        build(id*2 , l , mid);        build(id*2+1 , mid+1 , r);        tree[id].sum = tree[id * 2].sum + tree[id * 2 + 1].sum;        tree[id].max = max(tree[id * 2].max, tree[id * 2 + 1].max);    }}int main(){    int n;    while (cin >> n){        for (int i = 1; i <= n; i++){            cin >> a[i];        }        build(1,1,n);        cout << tree[1].max << endl << tree[1].sum;    }}/*6 // n1,5,4,1,6; // a[i]6 // cout(max)17 // cout(sum)*/
下面是对于线段树的一些操作。

线段树和树状数组有些类似。但比树状数组好用。首先是单点更新。

即修改某一点的数值。

源代码:

void change(int id,int pos,int val)//pos即为要修改的位置{    if (tree[id].L == tree[id].R)        tree[id].sum = tree[id].max = val;//val即更新的值    else    {        int mid = (tree[id].L + tree[id].R)/2;        if (pos <= mid)            change(id * 2,pos,val);        else            change(id * 2 + 1,pos,val);        tree[id].sum = tree[id * 2].sum + tree[id * 2 + 1].sum;        tree[id].max = max(tree[id * 2].max,tree[id * 2 + 1].max);    }}

接下来是另一项基本操作。和树状数组类似,就是查询某一段区间元素和和最大值。因为之前树种保存了,所以查询还是比较好实现的。

下面附查询总和的源代码:

int getsum(int id,int l,int r){    if (tree[id].L == l && tree[id].R == r)        return tree[id].sum;    else    {        int mid = (tree[id].L + tree[id].R)/2;        if (r <= mid)            return getsum(id * 2,l,r);        else if (l > mid)            return getsum(id * 2 + 1,l,r);        else            return getsum(id * 2,l,mid) + getsum(id * 2 + 1,mid + 1,r);    }}
下面附查询最大值的源代码:

int getmax(int id,int l,int r){    if (tree[id].L == l && tree[id].R == r)        return tree[id].max;    else    {        int mid = (tree[id].L + tree[id].R) / 2;        if (r <= mid)            return getmax(id * 2,l,r);        else if (l > mid)            return getmax(id * 2 + 1,l,r);        else            return max(getmax(id * 2,l,mid),getmax(id * 2 + 1,mid + 1,r));    }}

主函数:

int main(){    int n;    while (cin >> n){        for (int i = 1; i <= n; i++){            cin >> a[i];        }        build(1,1,n);        cout << tree[1].max << endl << tree[1].sum << endl;        cout << "l:" ;        int l,r;        cin >> l;        cout << endl << "r:";        cin >> r;        cout << endl;        cout <<"sum:" << getsum(1,l,r);        cout << "max:" << getmax(1,l,r);    }}


操作的事主要就是从头开始往下寻找。然后对这个线段树进行操作。可能还有别的操作,但是还没有学习还没有进行总结。以后再进行总结吧。

hdoj上有道题,看看把它做了吧。然后再去水几道JAVA作业题。

周末的练习赛,按时参加,赛后补题,记得记得!!


原创粉丝点击