树秀于林风必摧之——线段树

关于线段树,其实我一开始也是很懵的,但看久了也就习惯了。

  以下是我对线段树的一点理解,写得不好,也请各位看官见谅。

  搜狗定义:线段树(Segment Tree)是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

  定义还是很显然的。

  那么线段树都能做些什么呢?

  在n个数中有m个询问,询问如下:

  1.把q这个数改成v  O(logn);

  2.求在1~n这个区间的和.

  接下来我们讲原理(当然原理也是我自己的理解,可能不是正解,但我想,线段树这个东西大概就是这样的吧)

  首先看图

  

  下面我们将原理

  1.它是用“二进制”存储的

  什么是“二进制”存储?

  众所周知,用二的倍数可以表示所有的数

  例:13=1+4+8;

  (具体原理请参考二进制和十进制的转换)

  那么线段树也是这样:

  如:我们要查找(2,5)这个区间,那它就是2+(3,4)+5所代表的数(区间和)

  2.它是“二分查找”(当然不是严格意义上的)

  二分查找不再赘述

  例:当我们要把6这个位置上所在的数改为★,那我们一定是这样查找的:

  (1,8)->(5,8)->(5,6)->(6)->(★)

  那么怎么实现呢?我大概总结了一下几个步骤:

  1.建立线段树

  2.查找位置+动作

  具体代码如下

  

int a[maxn];//每个数的值
int sum[maxn*4];//区间和 

void update(int rt)
{
    sum[rt]=sum[rt*2]+sum[rt*2+1];//前缀和思想
} 

void build(int l,int r,int rt)//建立树,左孩子,右孩子,根
{
    if(l==r)
    {
        sum[rt]=a[l];
        return ;//边界
    }
    int m=(l+r)/2;
    build(1,m,rt*2);
    build(m+1,r,rt*2+1);
    update(rt);//合并两个儿子
} 

//如果不理解左孩子右孩子为什么要那样写的,看这里:

以根节点为例:(1)

左孩子:1*2=2;

右孩子:1*2+1=3;

这样就能保证树在数组里存满且不重复。

void modify(int l,int r,int rt,int p,int v)//将p的位置上的数改为v
{
    if(l==r)
    {
        sum[rt]=v;
        return ;//找到这个数了,改值。当然我们也会顺便把与它相关的所有值都改掉
    }
    int m=(l+r)/2;
    if(p<=m)
        modify(1,m,rt*2,p,v);
    else
        modify(m+1,r,rt*2+1,p,v);//二分查找
    update(rt);
} 

int query(int l.int r,int rt,int nowl,int nowr)//询问(nowl,nowr)这个区间和
{
    if(nowl<=1&&r<=nowr)//边界
        return sum[rt];
    int m=(l+r)/2;
    int ans=0;
    if(nowl<=m)ans+=query(1,m,rt*2,nowl,nowr);
    if(m<nowr)ans+=query(m+1,r,rt*2+1,nowl,nowr);//查找求和
    return ans;
}

这是两次询问。

主函数的话就依据情况调用这三个函数就好了

那我要讲的,大概就是这些了。

byebey!^_^

时间: 2024-12-18 15:59:25

树秀于林风必摧之——线段树的相关文章

非结构体线段树版 ZJU 1610 Count the Colors (线段树区间更新)

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different colors you can see at last. Input The first line of each data set contains exactly

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

【线段树】线段树系列 0.2单点修改区间求和线段树

1080 线段树练习 题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或者减去一个特定的值A.现在要求你能对每个提问作出正确的回答.1≤N<100000,,提问和修改的总数m<10000条. 输入描述 Input Description 输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数.接下一个正整数m,再接下来有m行,表示

【线段树】线段树系列 0.1单点修改单点求和线段树

终于搞定了单点修改线段树...3个月..操蛋..根本没有模板题..觉得太弱了...艹蛋...必须进一步更新我的版本啊 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; struct node { int left,right,value; }; node point[100]; int father[100]; int g; v

树套树+【UVALive】6709 Mosaic 二维线段树

题目链接:6709 Mosaic 题解:参考这个博客:二维线段树,先按行建树然后每一个节点也是一个棵线段树按列建. #include<bits/stdc++.h> #include<cmath> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #inclu

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc

木秀于林,风必摧之;行高于人,众必毁之?

前段时间在一本小说里面看到这句话,心里感触颇深,特地在此写下感想,简单分析下含义. 这句话原出自三国魏人李康的<运命论>.看到这句话,我想跟多人会为秀木和高人感到惋惜,怜悯之情油然而生.但是在我们感叹他们的摧折之后,是否静静想过,他们本身是否出了问题? 这句话告诉我们在一个团队里不能太标新立异太突出自己,虽然自身很优秀但必须学会适应环境.审时度势.不可清高自傲.一意孤行.我行我素;应虚怀若谷,团结同事,用自己的行动,带动大家的能动性和创造性.这样,你才能在社会上有一席之地. 另一方面,对自己要

线段树水题 #1077 : RMQ问题再临-线段树

#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> using namespace std; #define maxn 1000000 + 10 #define Lson L, mid, root<<1 #define Rson mid+1, R, root<<1|1 #define

讲解——线段树

   讲解--线段树 O.引例 A.给出n个数,n<=100,和m个询问,每次询问区间[l,r]的和,并输出. 一种回答:这也太简单了,O(n)枚举搜索就行了. 另一种回答:还用得着o(n)枚举,前缀和o(1)就搞定. 那好,我再修改一下题目. B.给出n个数,n<=100,和m个操作,每个操作可能有两种:1.在某个位置加上一个数:2.询问区间[l,r]的和,并输出. 回答:o(n)枚举. 动态修改最起码不能用静态的前缀和做了. 好,我再修改题目: C.给出n个数,n<=1000000,