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

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

这周一直在忙的还有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 // n
1,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作业题。

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值