线段树--数据结构专题学习

这两周是数据结构专题的学习,,被专题的题目虐得死去活来==

线段树:简单的说就是把【1,n】的区间二分,【1,(1+n)/2】左子树,【(1+n)/2+1,n】右子树

    就这样一直分下去,直到都是【x,x】这样的区间。这样就构成了一颗树了^-^

有这样一棵树,我们就可以在节点中储存区间的和啊,区间内的最大值啊,最小值等等。。这就是线段树的附加信息了,也是题目中的重点。。

    我们可以用一个数组(长度为k)储存原区间的初始值,然后根据这个建树,所以这个树的节点数最多为4*K;

    对于每个节点i,其左子树为i*2,右子树为i*2+1,父母节点为i/2。该区间的sum为左右子树区间和的和,最大最小值同理。。。

    线段树的建立,修改,查询都是用递归写的。

    所以在对单个数值时,必定会影响到其祖先节点,所以从上往下写。递归后修改节点信息。

    线段树的查询也是如此,从上向下查询。

    至于区间修改,,,我还在看。。。

    对了,修改和查询的复杂度都是lgn

    先贴模板

 1 struct node
 2 {
 3     int maxt,sum;
 4     int left,right;
 5 };
 6 struct node tree[4*K];
 7 int a[k];
 8 void build(int id,int l,int r)
 9 {
10     tree[id].left=l;tree[id].right=r;
11     if(l==r)
12     {
13         tree[id].maxt=tree[id].sum=a[l];
14     }
15     else
16     {
17         build(2*id,l,(l+r)/2);
18         build(2*id+1,(l+r)/2+1,r);
19         tree[id].maxt=max(tree[2*id].maxt,tree[2*id+1].maxt);
20         tree[id].sum=tree[2*id].sum+tree[2*id+1].sum;
21     }
22 }
23 int queryMax(int id,int l,int r)
24 {
25     if(l==tree[id].left && r==tree[id].right)
26         return tree[id].maxt;
27     int mid=(tree[id].left+tree[id].right)>>1;
28     int ret=0;
29     if(r<=mid)
30         ret=max(ret,queryMax(id<<1,l,r));
31     else if(l>=mid+1)
32         ret=max(ret,queryMax((id<<1)+1,l,r));
33     else
34     {
35         int a,b;
36         a=queryMax(id<<1,l,mid);
37         b=queryMax((id<<1)+1,mid+1,r);
38         return max(a,b);
39     }
40     return ret;
41 }
42 int update(int id,int pos,int v)
43 {
44     if(tree[id].left == tree[id].right)
45     {
46         tree[id].sum=tree[id].maxt=val;
47     }
48     else
49     {
50         int mid=(tree[id].left+tree[id].right)>>1;
51         if (pos<=mid) update(id*2,pos,v);
52             else update(id*2+1,pos,v);
53         tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
54         tree[id].maxt=max(tree[id*2].maxt,tree[id*2+1].maxt);
55     }
56     return 0;
57 }
58
59 int query(int id,int l,int r)
60 {
61         if (tree[id].left==l&&tree[id].right==r)
62             return tree[id].sum;
63         else
64         {
65             int mid=(tree[id].left+tree[id].right)>>1;
66             if (r<=mid) return query(id*2,l,r);
67             else if (l>mid) return query(id*2+1,l,r)
68             else return query(id*2,l,mid)+query(id*2+1,mid+1,r);
69         }
70     }

时间: 2024-08-10 19:15:00

线段树--数据结构专题学习的相关文章

线段树数据结构详解

线段树数据结构详解 Coded by Jelly_Goat. All rights reserved. 这一部分是线段树. 线段树,顾名思义,是一种树形数据结构,适用于各种求区间统一算法的动静两平衡的数据结构. 这里什么是统一算法?(自己口胡的统一算法) 比如求最大值or最小值.区间求和,一样的区间都是一样的算法,这也是和动态dp不同的地方. 前置知识1:二叉搜索树 二叉搜索树就是根节点比左儿子大,比右儿子小的一种二叉树. 前置知识2:向量存储 向量存储是用来存完全二叉树儿子和父亲关系的. 如果

线段树 数据结构的简介和 leetcode 307

之前一直听说线段树是一个很高级很难的数据结构,今天简单了解了下, 感觉就是二叉树加几个全局变量啊,原来这么easy?(开个玩笑) 简单说几个特点, 1. 每个节点除了存放left,right指针之外,还存着一个范围(这个范围一般是构建线段树之前数组的索引范围), 就是以当前节点为根的情况下,对自己下面所有节点的求交集, 还可以根据你的需求 加一些别的特殊字段,sum,max,min等等 2. 数据集都存在叶子节点上,非叶子节点只做归纳总结 一般还有几个操作 1. 初始化,就是把一个数组初始化成一

线段树基础

关于线段树的原理学习,可以参看杨弋大牛的论文<线段树>以及刘汝佳老师的<算法竞赛入门经典(训练指南)>,代码风格学习hzwer或者notonlysuccess均可. 一.单点更新 最基础的线段树 题目:codevs1080 链接:http://codevs.cn/problem/1080/ 分析:最简单的线段树,单点更新,区间求和 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4

ACM: 敌兵布阵 解题报告 -线段树

敌兵布阵 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description Lily 特别喜欢养花,但是由于她的花特别多,所以照料这些花就变得不太容易.她把她的花依次排成一行,每盆花都有一个美观值.如果Lily把某盆花照料的好的话,这盆花的美观值就会上升,如果照料的不好的话,这盆花的美观值就会下降.有时,Lily想知道某段连续的花的美观值之和是多少,但是,Lily的算术不是很好,你能快

北大ACM3468——A Simple Problem with Integers~~线段树的应用

题目的意思很明确,有两种操作,一种是计算一个数列的第 a 到 第b的和,另一种是第 a 到 第 b 之间的数加上 c.由于这些操作的数目很大,用普通的办法无法办到,会超时. 对于这类问题,用线段树可以很好解决.对于线段树还只是学习阶段,还不是很熟,需要多加练习与理解. #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef __int64 ll; cons

hdu1394Minimum Inversion Number(线段树,求最小逆序数)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 25092    Accepted Submission(s): 14816 Problem Description The inversion number of a given number sequence a1, a2, ..., a

Bailian 2808 校门外的树(入门线段树)

题目链接:http://bailian.openjudge.cn/practice/2808?lang=en_US 总时间限制: 1000ms 内存限制: 65536kB 描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,--,L,都种有一棵树.马路上有一些区域要用来建地铁,这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域

暑假集训8.7数据结构专题-很妙的线段树( 觉醒力量(hidpower))

题目:oj1710 因为存在修改和查询的操作,所以学长说可以很"轻易"的想到线段树....,装作我轻易的想到了,最后是要输出答案mod17及mod46189的结果,(关键点1)然后我们发现46189=11*13*17*19:于是我们想到但处理出答案mod每个质因数的答案,再利用中国剩余定理求出答案.(关键点2)考虑对枚举进入某各区间运算的数为1-p[i],因为p[i]很小所以可以处理.然后修改操作也变成log的.非常可写. 关于中国剩余定理:x=(∑ai*ti*mi)modM.ti是逆

暑假集训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,