【转】POJ 3264 线段树解法

每个算法都是数学家或者计算机学家多年研究的结果,不是我自己臆造的,所以学习一个新算法的最佳方法还是看写的好的代码。

按照惯例,我就粘贴一个网上写的很好的帖子。。。

原文地址:http://ip96cns.blog.163.com/blog/static/17009519220112525029459/

线段树的查找:(感谢高手指点,虽然只是一点却让我把线段树的内容理顺了)这里是我的一些总结吧

          一个线段树的结点表示一个区间,同时结点中保存所需要的信息。

         如果询问区间正好为这个线段树的区间(左边界和右边界都相同),则返回该结点中保存的信息。

         否则,递归往下查询该结点的子结点(之后再返回的值就是子结点的值了,与当前结点无关了)

         一直到“元线段”-不可再分之线段。

         线段树的结点的区间包含所有子结点的区间,并且子结点只有两个,同时子结点区间为父结点的一半,(二叉树)

         往下查询的时候判断询问区间是否与当前结点表示区间的左右区间覆盖,有三种情况

        1,查询区间在该结点表示区间中点右边,此时只需要往右孩子查询

        2.查询区间在该结点表示区间中点左边,此时只需要往左孩子查询

        3.查询区间包含该结点中点,这个时候要把查询区间一分为2,即查询区间的左边界到中点,往左孩子查询,以及中点到查询区间的右边界,往右孩子查询。 

 

 

这里线段树我用了两种实现方式,不过在渐进复杂度上差别不大。当然这题目RMQ才够快的。

我传了两个引用进去分别用来返回最大最小值。。。

 

第一种方法:

          .从1~n区间建立静态树,然后先给区间[i,i](就是左右边界相等的区间)赋值,然后再写个函数求其他区间。

第二种方法:

          从1~n区间建立静态树,并且将其中最大最小值构造为极小和极大,接着对于每个输入数据,不断的包含该数据所属区间的最大最小值.比如说某个数据i在区间[l,r]中,修改这个区间的结点,然后再递归下去修改这个结点的子结点的区间.

(这样就不需要为输入数据的开辟一个数组,但是效果似乎似乎不太好。)

#include <iostream>
#include <stdio.h>
using namespace std;

struct node
{
 int l,r;
 int minvalue,maxvalue;
};
node nodes[10000000];
//
int cowheight[50010];
//
void queryinterval(int l,int r,int nodeindex,int& maxval,int& minval)
{
 if(nodes[nodeindex].l==l&&nodes[nodeindex].r==r)
 {
  maxval=nodes[nodeindex].maxvalue;
  minval=nodes[nodeindex].minvalue;
  return ;
 }
 if(l==r)
 {
  maxval=minval=cowheight[l];
  return ;
 }
 //
 int mid=(nodes[nodeindex].l+nodes[nodeindex].r)/2;
 // 这个地方调试了很久才发现。。。如果这里不错就节省半天了
 // mid=(l+r)/2 是错的,必须是mid=(nodes[nodeindex].l+nodes[nodeindex].r)/2
 if(l>mid) queryinterval(l,r,nodeindex*2+2,maxval,minval);
 else if(r<=mid) queryinterval(l,r,nodeindex*2+1,maxval,minval);
 else
 {
  int max1,min1,max2,min2;
  queryinterval(l,mid,nodeindex*2+1,max1,min1);
  queryinterval(mid+1,r,nodeindex*2+2,max2,min2);
  maxval=max1>max2?max1:max2;
  minval=min1<min2?min1:min2;
  return ;
 }
}
//
//
void creattree(int l,int r,int index)
{
 nodes[index].l=l;
 nodes[index].r=r;
 if(l==r)
 {
  nodes[index].maxvalue=nodes[index].minvalue=cowheight[l];
  return;
 }
 creattree(l,(l+r)/2,index*2+1);
 creattree((l+r)/2+1,r,index*2+2);
}
void addvalue(int index,int& maxval,int& minval)
{
 if(nodes[index].l==nodes[index].r)
 {
  minval=maxval=nodes[index].maxvalue;
  return ;
 }
 int max1,min1,max2,min2;
 addvalue(index*2+1,max1,min1);
 addvalue(index*2+2,max2,min2);
 nodes[index].maxvalue=max1>max2?max1:max2;
 nodes[index].minvalue=min1<min2?min1:min2;
 maxval=nodes[index].maxvalue;
 minval=nodes[index].minvalue;
 return ;
}
//
int main()
{
 int n,q;
 scanf("%d%d",&n,&q);
 //
 int i;
 for(i=1;i<=n;i++)
  scanf("%d",&cowheight[i]);
 //建树
 creattree(1,n,0);
 int l,u;
 addvalue(0,l,u);
 //
 for(i=0;i<q;i++)
 {
  int a,b;
  scanf("%d%d",&a,&b);
  int maxval,minval;
  queryinterval(a,b,0,maxval,minval);
  printf("%d\n",maxval-minval);
 }
 return 0;
}
#include <iostream>
#include <stdio.h>
using namespace std;
struct node
{
int l,r;
int minvalue,maxvalue;
node(){maxvalue=0; minvalue=0x7fffffff; }
}; node nodes[131072];
//
//
void queryinterval(int l,int r,int nodeindex,int& maxval,int& minval)
{
if(nodes[nodeindex].l==l&&nodes[nodeindex].r==r)
{
maxval=nodes[nodeindex].maxvalue;
minval=nodes[nodeindex].minvalue;
return ;
}
//
int mid=(nodes[nodeindex].l+nodes[nodeindex].r)/2;
if(l>mid) queryinterval(l,r,nodeindex*2+2,maxval,minval);
else if(r<=mid) queryinterval(l,r,nodeindex*2+1,maxval,minval);
else
{
int max1,min1,max2,min2;
queryinterval(l,mid,nodeindex*2+1,max1,min1);
queryinterval(mid+1,r,nodeindex*2+2,max2,min2);
maxval=max1>max2?max1:max2;
minval=min1<min2?min1:min2;
return ;
}
}
//
//
void creattree(int l,int r,int index)
{
nodes[index].l=l;
nodes[index].r=r;
if(l<r)
{
creattree(l,(l+r)/2,index*2+1);
creattree((l+r)/2+1,r,index*2+2);
}
}
void addvalue(int pos,int val,int nodeindex)
{
if(nodes[nodeindex].l==nodes[nodeindex].r)
{
nodes[nodeindex].maxvalue=nodes[nodeindex].minvalue=val;
return ;
}
//
if(nodes[nodeindex].maxvalue<val) nodes[nodeindex].maxvalue=val;
if(nodes[nodeindex].minvalue>val) nodes[nodeindex].minvalue=val;
//
int mid=(nodes[nodeindex].l+nodes[nodeindex].r)/2;
if(pos<=mid) addvalue(pos,val,nodeindex*2+1);
else         addvalue(pos,val,nodeindex*2+2);
}
//
int main()
{
int n,q;
scanf("%d%d",&n,&q);
//
creattree(1,n,0);
int i,cowheight;
for(i=1;i<=n;i++)
{
scanf("%d",&cowheight);
addvalue(i,cowheight,0);
}
//
for(i=0;i<q;i++)
{
int a,b;
scanf("%d%d",&a,&b);
int maxval,minval;
queryinterval(a,b,0,maxval,minval);
printf("%d\n",maxval-minval);
}
return 0;
}
时间: 2024-10-21 21:19:09

【转】POJ 3264 线段树解法的相关文章

POJ 3468 线段树 区间更新区间查询

题意:给出一段数列,任意区间加上一个整数v,任意区间查询.给出N个数,Q次操作. 线段树的题,延迟指针不更新到底就行了. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 long long sum[maxn<<2],col[maxn<<2]; void

poj 1171 Picture 线段树

     经典的线段树问题,看了好久才看懂      解法很简单,按y坐标从小到大,依次扫描每条线段,每次利用线段树记录当前图形在x轴上的投影,然后用这次投影减去上次就是x轴上变化量,而y轴,因为按y轴枚举,只需要用y的差值乘以2再乘以当前线段数即可.      而线段树的处理就是遇到下边是加入线段树,遇到上边删去及记录当前投影长度,及投影分段情况      看到网上还有种括号匹配的方法,离散化后枚举,复杂度n^2 /* author:jxy lang:C/C++ university:Chin

poj 2528 Mayor&#039;s posters(线段树+离散化)

/* poj 2528 Mayor's posters 线段树 + 离散化 离散化的理解: 给你一系列的正整数, 例如 1, 4 , 100, 1000000000, 如果利用线段树求解的话,很明显 会导致内存的耗尽.所以我们做一个映射关系,将范围很大的数据映射到范围很小的数据上 1---->1 4----->2 100----->3 1000000000----->4 这样就会减少内存一些不必要的消耗 建立好映射关系了,接着就是利用线段树求解 */ #include<ios

线段树和RMQ解析和模板

这几天在看RMQ的题目,但是很多RMQ的题目也可以用线段树解决... 看来两者之间有很多关系,那就都好好看吧...下面先贴出一个大牛对两者的解释.. RMQ (Range Minimum/Maximum Query)问题是指: 对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在[i,j]里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题  主要方法及复杂度(处理复杂度和查询复杂度)如下:  1.朴素(即搜索) O(n)-O(n)  2.线段树(se

poj 3264 Balanced Lineup【RMQ】

这道题是poj上面RMQ最具代表性的一道题,没有之一 题目也基本上就是一个裸RMQ的算法,看到这道题也可以用线段树解决,决定还是要出一个线段树的版本的,一道题搞懂两个知识点,多好! RMQ(Range Minimum/Maximum Query)问题:      RMQ问题是求给定区间中的最值问题.当然,最简单的算法是O(n)的,但是对于查询次数很多(设置多大100万次),O(n)的算法效率不够.可以用线段树将算法优化到O(logn)(在线段树中保存线段的最值).不过,Sparse_Table算

POJ3468&amp;#160;线段树-模板题

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

线段树(Segment Tree)

1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即"子数组"),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 使用线段树可以

hdu 4614 Vases and Flowers 线段树

    比赛最后40分钟写的,线段树加二分,思路写法完全没问题,但最后提交了2次都WA了,回来后发现是模板更新lazy把0当做更新过的了,但是应该是1 /* author:jxy lang:C/C++ university:China,Xidian University **If you need to reprint,please indicate the source** */ #include <iostream> #include <cstdio> #include <

c++-帮我看一下这段线段树的代码应该怎么用?有问题吗?

问题描述 帮我看一下这段线段树的代码应该怎么用?有问题吗? #include#define MAXN 10005struct node{ int left; int right; int mid; int cover;};node SegTree[3*MAXN];void BuildSegTree(int lint rint num){ SegTree[num].left=l; SegTree[num].right=r; SegTree[num].mid=(l+r)/2; if(l+1!=r)