题目:

输入两个数(m,n),m表示牛的头数,n表示查询的个数。
查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,000 设计每次查询的复杂度为logm。

例如,

输入:

6 3
1
7
3
4
2
5
1 5
4 6
2 2
输出:
6
3
0
 

 
分析:这道题是典型的空间换时间的题。一看到是区间的查找,我们应该想到线段树,这里有一篇我觉得写得挺好的介绍线段树的博客和大家分享一下:http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464583.html
 
1.根据输入m值,建立线段树。public void buildTree(int m) 
2.根据输入的牛的体重,初始化线段树。public void initTree(SNode sn, int value)
3.根据查询,查询线段树。public void find(SNode sn, int a, int b)
 
首先我们来看建立线段树。由于要查询的是最大值与最小值之差,所以在线段树中每个结点除了要存储范围的左右阈值和左右子节点的引用外,还要存储该区间内的最大值最小值。以6头牛为例,设编号为1-6,那么最终构建的线段树应该如下图所示:
 
分析一下建树的递归过程。
首先,终止条件是:first==last(以结点1为例,那么,first=1,last=1);
然后,递归的共同操作是:为结点中的first和last赋值,表明结点的范围,即

node.first = first,node.last = last;

接着,看递归的参数:通过前面的分析可知,肯定有一个结点引用的参数node,然后因该要有结点的范围,即first和last;

最后,看递归的过程:递归的过程无非就是左右子树递归,即:

node.left = new SNode();
node.right = new SNode();
build(node.left, first, ( first + last) / 2);
build(node.right, ( first + last) / 2 + 1, last);
在这里注意:为什么要先给左右子节点的引用赋值,因为在java中,不先给赋值的话,没有分配指向的地址,参数传递之后,是对参数进行的赋值,返回之后原结点还是指向null的。下图分析这个值传递的过程:

node1先new的过程就相当于node1先指向了堆中的node,然后,node1拷贝到node2,node2也指向node,那么用node2修改node和node1修改node就是一样的效果。

 
理解了建立线段树的过程,后面初始化线段树和查找的过程也是类似的方法,这里就不详述了,直接上代码吧。
 

代码:

package study;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer; /**
* http://poj.org/problem?id=3264
 * 输入两个数(m,n),m表示牛的头数,n表示查询的个数。
* 查询结构如下(x,y),这个区间内牛重量的最大值减去,牛重量的最小值,为查询结果, 数量级为100,0000 设计每次查询的复杂度为logm。
*
* @author cnx
* @CreateDate ; 2014年9月28日 下午9:38:25
*/
public class SegmentTree {
public static void main(String[] args) throws IOException {
SegmentTree s = new SegmentTree();
BufferedReader stdin = new BufferedReader(new InputStreamReader(
System.in)); String line = stdin.readLine();
StringTokenizer st = new StringTokenizer(line);
s.m = Integer.parseInt(st.nextToken());
s.n = Integer.parseInt(st.nextToken());
//建树,并初始化结点
s.buildTree(s.m);
for (s.inc = 1; s.inc <= s.m; s.inc++) {
line = stdin.readLine();
st = new StringTokenizer(line);
int value = Integer.parseInt(st.nextToken());
s.initTree(s.sn, value);
}
//输入查询,并给出结果
for (int i = 0; i < s.n; i++) {
line = stdin.readLine();
st = new StringTokenizer(line);
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
s.max = 0;
s.min = 99999999;
s.find(s.sn,a,b); System.out.println(s.max-s.min);
} } public int m;
public int n;
public SNode sn = new SNode(); public int inc;
public int max;
public int min; /**
* 线段树结点类
* @author cnx
* @CreateDate ; 2014年9月29日 上午9:17:55
*/
public static class SNode {
int first;
int last;
int max;
int min = 9999999;
SNode left ;
SNode right ;
}
/**
* 构建线段树
* @param m 范围为1-m
*/
public void buildTree(int m) {
build(sn, 1, m);
}
/**
* 构建线段树的递归函数
* @param node
* @param L 线段树结点中的first,即范围的左阈值
* @param R 结点中的last,即范围的右阈值
*/
public void build(SNode node, int L, int R) {
if(node == null)
node = new SNode();
node.first = L;
node.last = R;
if (L == R) {
return;
} node.left = new SNode();
node.right = new SNode();
build(node.left, L, (L + R) / 2);
build(node.right, (L + R) / 2 + 1, R);
}
/**
* 给线段树的max和min字段赋值
* @param sn
* @param value 输入的值
*/
public void initTree(SNode sn, int value) {
if (value > sn.max) {
sn.max = value;
}
if (value < sn.min) {
sn.min = value;
}
if (sn.first == sn.last) {
return;
}
if (inc > (sn.last + sn.first) / 2) {
initTree(sn.right, value);
} else {
initTree(sn.left, value);
}
}
/**
* 在线段树中查找,范围a-b的最大值和最小值
* @param sn
* @param a
* @param b
*/
public void find(SNode sn, int a, int b){ if (sn.first==a && sn.last==b) {
if (sn.max>max) {
max = sn.max;
}
if (sn.min<min) {
min = sn.min;
}
return;
} if (b<=(sn.first+sn.last)/2) {
find(sn.left, a, b);
}
else if (a>(sn.first+sn.last)/2) {
find(sn.right, a, b);
}
else {
find(sn.left, a, (sn.first+sn.last)/2);
find(sn.right, (sn.first+sn.last)/2+1, b);
}
} }

POJ——3264线段树的更多相关文章

  1. poj 3264 线段树 求区间最大最小值

    Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same ...

  2. POJ - 3264 线段树模板题 询问区间最大最小值

    这是线段树的一个模板题,给出一串数字,然后询问区间的最大最小值. 这个其实很好办,只需把线段树的节点给出两个权值,一个是区间的最小值,一个是区间的最大值,初始化为负无穷和正无穷,然后通过不断地输入节点 ...

  3. POJ 3264 线段树入门解题报告

    题意:给n个值, Q次询问, 每次询问给定一个区间, 要求输出该区间最大最小值之差 思路:暴力的话每次询问都要遍历多次for循环一定会超时, 用线段树记录区间的信息(左边界右边界, 该区间最大值最小值 ...

  4. poj 3264 线段树

    题目意思:给定Q(1<=Q<=200000)个数A1,A2,```,AQ, 多次求任一区间Ai-Aj中最大数和最小数的差 线段树太弱了,题目逼格一高连代码都读不懂,今天开始重刷线段树,每天 ...

  5. POJ 3264 线段树 ST

    题意:给你一个数列,从中挑一段,问你这段数的最大值减最小值是多少. 思路:线段树. // by Sirius_Ren #include <cstdio> #include <algo ...

  6. G - Balanced Lineup POJ - 3264 线段树最大最小值区间查询模版题

    题意 给出一个序列  每次查询区间的max-min是多少 思路:直接维护max 和min即可  写两个query分别查最大最小值 #include<cstdio> #include< ...

  7. poj 2886 线段树+反素数

    Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 12744   Acc ...

  8. poj 3468(线段树)

    http://poj.org/problem?id=3468 题意:给n个数字,从A1 …………An m次命令,Q是查询,查询a到b的区间和,c是更新,从a到b每个值都增加x.思路:这是一个很明显的线 ...

  9. POJ 2828 线段树(想法)

    Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 15422   Accepted: 7684 Desc ...

随机推荐

  1. 全局对象的构造函数会在main 函数之前执行

    #include <iostream> using namespace std; class A { public: A() { cout << "Generator ...

  2. 时间和日期控件(Calendar1)

    取得选择的: taskItem["data"] = Calendar1.SelectedDate.ToShortDateString();

  3. Debian上安装Apache+Django全过程

    -->start sudo apt-get install apache2 libapache2-mod-wsgi #https://wiki.debian.org/zh_CN/Apache s ...

  4. (转)C++0x语言新特性一览

    转自:http://blog.csdn.net/zwvista/article/details/2429781 原文请见http://en.wikipedia.org/wiki/C%2B%2B0x. ...

  5. ACM/ICPC 之 差分约束系统两道(ZOJ2770-POJ1201)

    当对问题建立数学模型后,发现其是一个差分方程组,那么问题可以转换为最短路问题,一下分别选用Bellmanford-SPFA解题 ZOJ2770-Burn the Linked Camp //差分约束方 ...

  6. windows编程中关于“关闭窗口无法退出进程”的解决方法

    一般会出现如下两种情况 1.WinMain函数中,最后阶段接收消息队列循环中,调用的GetMessage函数参数提供错误 如: while (GetMessage(&msg,hwnd, 0, ...

  7. ghost xp 安装IIS,并配置WCF

    因要一台电脑做WCF服务的测试服务器,但只有一个台式机可能,配置就不用说了,2G内存.之前装的是win7,卡得要死.于是就想把它装回XP系统.但在网上找来找去,都是ghost xp,之前还很怕ghos ...

  8. android学习————项目导入常见错误整理(转载)

    详细请访问http://4789781.blog.51cto.com/4779781/1031107

  9. myEclipse中改了项目名,出现的问题 和 错误java.io.IOException: tmpFile.renameTo(classFile) failed

    今天遇到一个很头疼的问题,建的一个新项目,后来因为一些原因把项目名改了,之后就做了一些业务,但运行时总是没有反应,后来在myEclipse工作空间下的webapps文件中发现, 部署的文件名和项目名称 ...

  10. linux日常易忘指令

    1.编辑全局指令 进入~/.bash_profile 增加"exprot +(启动文件的地址)" source ~/.bash_profilr(刷新) 2.修改mysql密码 my ...