开学第二周了。也终于逐渐稳定下来可以有条有序的处理问题了。首先说一点到现在为止的一点不足的地方,就是还没有去实验室学过习。这周末就要去做比赛了,周围都是大佬压力好大。。。
这周一直在忙的还有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作业题。
周末的练习赛,按时参加,赛后补题,记得记得!!