数据结构之线段树

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。

因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

用线段树解题关键是要清楚的知道每个节点要存放什么信息,以及这些节点如何高效的更新,维护,查询,不一定每次都更新到叶子节点,这样复杂度最坏有可能是0(n)

下面附上一道题

poj3264

思路:用一维数组存放节点,节点数<=4n-1,每个节点存放该区间的最大值,最小值

代码

#include<iostream>
#include<stdio.h>
using namespace std;
const int INF=100000000;
int minV=INF;
int maxV=-INF;
int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a>b?b:a;
}

//节点信息
struct Note
{
    int L,R;
    int minV,maxV;
    int Mid()
    {
        return (L+R)/2;
    }
};Note tree[800010];

//建树
void buildtree(int root,int L,int R)
{
    tree[root].L=L;
    tree[root].R=R;
    tree[root].minV=INF;
    tree[root].maxV=-INF;
    if(L!=R)
    {
        buildtree(root*2+1,L,(L+R)/2);
        buildtree(root*2+2,(L+R)/2+1,R);
    }
}

//插入
void insert(int root,int i,int v)
{
    if(tree[root].L==tree[root].R)
    {
        tree[root].minV=tree[root].maxV=v;
        return ;
    }
    tree[root].minV=min(v,tree[root].minV);
    tree[root].maxV=max(v,tree[root].maxV);
    if(i<=tree[root].Mid())
    {
        insert(2*root+1,i,v);
    }
    else
    {
        insert(2*root+2,i,v);
    }
}

//查询
void chaxun(int root,int s,int e)
{
    if(tree[root].minV>=minV&&tree[root].maxV<=maxV)
    {
        return ;
    }
    if(tree[root].L==s&&tree[root].R==e)
    {
        minV=min(minV,tree[root].minV);
        maxV=max(maxV,tree[root].maxV);
        return ;
    }
    if(e<=tree[root].Mid())
    {
        chaxun(2*root+1,s,e);
    }
    else if(s>tree[root].Mid())
    {
        chaxun(2*root+2,s,e);
    }
    else
    {
        chaxun(2*root+1,s,tree[root].Mid());
        chaxun(2*root+2,tree[root].Mid()+1,e);
    }
}
int main()
{
    int p,n;
    int i,h;
    while(scanf("%d%d",&n,&p)!=-1)
    {
        buildtree(0,1,n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&h);
            insert(0,i,h);
        }
        for(i=0;i<p;i++)
        {
            int s,e;
            scanf("%d%d",&s,&e);
            minV=INF;
            maxV=-INF;
            chaxun(0,s,e);
            printf("%d\n",maxV-minV);
        }
    }
    return 0;
}

时间: 2024-11-03 20:54:51

数据结构之线段树的相关文章

《数据结构》线段树入门(二)

今天继续介绍——线段树之延迟标记 接上期<数据结构>线段树入门(一):http://www.cnblogs.com/shadowland/p/5870339.html 在上期介绍了线段树的最基本内容(线段树单点修改,区间查询),这次将介绍:区间修改,区间查询. Question: 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述: 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,每行表示操作的个数,如果第一数是1,后接3个正

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将

《数据结构》线段树入门(一)

今天介绍一种非常特殊的数据结构——线段树 首先提出一个问题: 给你n个数,有两种操作: 1:给第i个数的值增加X 2:询问区间[a,b]的总和是什么? 输入描述 输入文件第一行为一个整数n,接下来是n行n个整数,表示格子中原来的整数.接下一个正整数q,再接 下来有q行,表示q个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给 位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和. 样例输入 4 7 6 3 5 2 1 1

【数据结构】线段树 (定义 &amp; 点修改/区间查询)

[本文描述高级数据结构线段树的定义] [并解决 点修改/区间查询 的问题] 结构与定义 线段树的基本结构 ? 由图可知,线段树的每一个节点都代表着一段区间 且同一层的节点(深度相同的节点)所表示的区间互不重叠 所有叶子节点代表的区间左边界与右边界相同(叶子节点代表单个元素) 普遍规定 如果某个非叶子节点代表的区间包含元素个数为奇数 则它的左儿子包含的元素个数比右儿子大 1 在代码部分,非叶子节点表示区间为 [l,r] 则左儿子为 [ l , (l+r)/2 ] ,右儿子为 [ (l+r)/2+1

数据结构2——线段树

一.相关介绍 线段树:它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题.由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn). 线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]. 下面我们从一个经典的例子来了解线段树,问题描述如下: 从数组arr[0...n-1]中查找某个(子)数组内的最小值,其中数组大小固定,但是数组中

【数据结构】线段树入门

线段树是一种二叉搜索树. 它将一个区间划分成一些子区间,每个子区间对应线段树中的一个叶节点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)>>1],右儿子表示的区间为[(a+b)>>1+1,b].也就是说线段树是一棵平衡二叉树. 下图是对于[1,10]的区间构造的一棵线段树. 线段树的基本操作函数有三个. 分别是build(建树),update(更新),query(查询区间和). 线段树定义: struct node{ int left,righ

数据结构(线段树):BZOJ 1568 [JSOI2008]Blue Mary开公司

1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 602  Solved: 214[Submit][Status][Discuss] Description Input 第 一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益. 若单词为Project,则

【数据结构】线段树(interval tree)

线段树(interval tree),也叫区间树.也是一种二叉搜索树,同一般的BST不同之处在于:线段树的每一个结点包含的是一个区间而不是一个数.具体的描述如下: 从图上可以看出,线段树的每一个结点都是一个线段(区间),子节点是对父结点的进一步分划,每个子节点的长度都是父节点的二分,每个叶子结点就是一个元素. 每个节点可以用一个变量hit_count来计算在每一段的命中率,这样可以用来统计此线段线段或者区间内的命中率. 区间树主要用在一些跟统计和分部相关的计算中,可以快速找到相应的数据.

暑假集训8.7数据结构专题-线段树存直线

题目: E-card oj1811 思路:线段树内存直线的k和b,线段树存x,当某个区间的左右端点代入关系始终严格优于或劣于带修改的值,则修改区间.否则继续分散到两个子区间重复操作. 代码: #include<bits/stdc++.h> #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=100005; struct node{int l,r,a,