一切的折腾都来源于这里:http://acm.nyist.net/JudgeOnline/problem.php?pid=9
的这道题posters题,全英文的。解题的知识点:线段树+离散化。
http://chenhongyu940407.blog.163.com/blog/static/20500925420127240398325/ 这里有整道题的思路+代码。
这道题让我重新认识了一个数据结构--线段树,看了大概一个钟,也只能一知半解。总之,个人理解是:线段树是为了解决在某段区间内,找最小值或者是最大值。
http://dongxicheng.org/structure/segment-tree/ --董的博客 -->他讲得比较清楚,但缺少完整的代码。---先重这里开始理解。
进阶:
http://www.cnblogs.com/TenosDoIt/p/3453089.html JustDoIT---有具体的代码实现。
还是那句话,看懂了,和写出来时两回事,即使是对着打,在打的过程中,也会有新的理解。
下面是自己对着JustDoIT写的,--线段树的创建和查询,其他不够理解,以后继续更新吧。
package structure;
/*
* 数据结构---线段树
*/
public class LineSegmentTree {
public static void main(String[] args) {
}
public static final int MAXNUM=1000;
//线段树的节点
class SegTreeNode{
int val;
}
SegTreeNode[] segTreeNode=new SegTreeNode[MAXNUM]; //定义线段树
/*
功能:构建线段树
root:当前线段树的根节点下标
arr: 用来构造线段树的数组
istart:数组的起始位置
iend:数组的结束位置
*/
public void build(int root,int[] arr,int iStart,int iEnd){
if(iStart==iEnd) //叶子节点
segTreeNode[root].val=arr[iStart];
else{
int mid=(iStart+iEnd)>>1; //右移一位,相当于/2
build(root*2+1,arr,iStart,mid); //递归构造左子树 root*2+1,因为是线段树相当于完全二叉树,
build(root*2+2,arr,mid+1,iEnd); //递归构造右子树 而且是数组进行构造,root*2+1代表此时所在的位置(完全二叉树的性质)
//根据左右子树根节点的值,更新当前根节点的值--根节点存最小
segTreeNode[root].val = segTreeNode[root*2+1].val<segTreeNode[root*2+2].val?segTreeNode[root*2+1].val:segTreeNode[root*2+1].val;
}
}
/*
功能:线段树的区间查询
root:当前线段树的根节点下标
[nstart, nend]: 当前节点所表示的区间
[qstart, qend]: 此次查询的区间
*/
public int query(int root,int nstart,int nend,int qstart, int qend){
//查询区间和当前节点区间没有交集
if(qstart>nend||qend<nstart)
return -1; //表示错误
//当前节点区间包含在查询区间内
if(qstart<=nstart&&qend<=nend)
return segTreeNode[root].val;
//分别从左右子树查询,返回两者查询结果的较小值
int mid = (nstart + nend) / 2;
return min(query(root*2+1,nstart,mid,qstart,qend),query(root*2+2,mid+1,nend,qstart,qend));
}
public int min(int a,int b){
if(a<b)
return a;
return b;
}
}