最近学线段树,先来总结一下知道的基础知识。感觉这东西很灵活。

  自己现在的理解就是线段树是来维护一个序列的区间查找与修改操作的数据结构,我觉得学好它可能更容易理解树状数组。就像有的网站上说,为什么需要线段树,就是因为它综合起来查找和修改的操作复杂度比较低,都是log级别的。基本线段树都包括Build(),Update(),Query(),PushUp()函数。A[]数组存维护的原序列,sum[]数组存区间和。sum[]数组的下标其实是这棵树从根节点到叶子节点的编号,每个编号对应一个区间和,自然sum[1]对应所维护的整个区间。由于sum[]数组不仅存每个点的值,还存区间的值,所以数组要开相当于A[]数组的4倍。

单点更新类:

HDU 1166  线段树功能:update:单点增减 query:区间求和

这是到入门题。说的也很直白,就是区间的查询和修改。用宏定义lson,rson方便一些。

 1 #include<cstdio>
 2 #define lson l,m,rt<<1
 3 #define rson m+1,r,rt<<1|1
 4 using namespace std;
 5 const int maxn=50005;
 6 int A[maxn],sum[maxn<<2];
 7
 8 void PushUp(int rt)
 9 {
10     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
11 }
12
13 void Build(int l,int r,int rt)//递归建树
14 {
15     if(l==r){
16         sum[rt]=A[l];//递归到叶子节点时,把初始值给对应的sum[]数组的值。
17         return;
18     }
19     int m=(l+r)>>1;
20     Build(lson);
21     Build(rson);
22     PushUp(rt);//向上更新父节点的值,刚开始建树时只有存叶子结点值的sum[]有值。
23 }
24
25 void Update(int pos,int val,int l,int r,int rt)//递归更新
26 {
27     if(l==r){
28         sum[rt]+=val;
29         return;
30     }
31     int m=(l+r)>>1;
32     if(pos<=m) Update(pos,val,lson);
33     else Update(pos,val,rson);
34     PushUp(rt);//也是要向上返回更新父节点
35 }
36
37 int Query(int L,int R,int l,int r,int rt)
38 {
39     if(L<=l&&r<=R){//属于[L,R]直接返回
40         return sum[rt];
41     }
42     int m=(l+r)>>1;
43     int res=0;
44     if(L<=m)  res+=Query(L,R,lson);//有交叉就递归
45     if(R>m) res+=Query(L,R,rson);
46     return res;
47 }
48
49 int main()
50 {
51     int T;
52     scanf("%d",&T);
53     for (int cas=1;cas<=T;cas++)
54     {
55         int N;
56         scanf("%d",&N);
57         for (int i=1;i<=N;i++) scanf("%d",&A[i]);
58         Build(1,N,1);
59         printf("Case %d:\n",cas);
60         char op[10];
61         while(scanf("%s",op))
62         {
63             int a,b;
64             if(op[0]=='E') break;
65             scanf("%d%d",&a,&b);
66             if(op[0]=='Q')
67                 printf("%d\n",Query(a,b,1,N,1));
68             else if(op[0]=='A')
69                 Update(a,b,1,N,1);
70             else
71                 Update(a,-b,1,N,1);
72         }
73     }
74     return 0;
75 }

hdu 1166

HDU 1754 线段树功能:update:单点替换 query:区间最值

这道题就是在把sum[]数组的存区间和作用变为存区间的最大值。所以就把sum[]变成MAX[]了。其实道理是一样的。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define lson l,m,rt<<1
 4 #define rson m+1,r,rt<<1|1
 5 using namespace std;
 6 const int maxn=200005;
 7 int MAX[maxn<<2],A[maxn];
 8 int N,M;
 9
10 void PushUp(int rt)
11 {
12     MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
13 }
14
15 void Build(int l,int r,int rt)
16 {
17     if(l==r){
18         MAX[rt]=A[l];
19         return;
20     }
21     int m=(l+r)>>1;
22     Build(lson);
23     Build(rson);
24     PushUp(rt);
25 }
26
27 void Update(int pos,int val,int l,int r,int rt)
28 {
29     if(l==r){
30         MAX[rt]=val;
31         return;
32     }
33     int m=(l+r)>>1;
34     if(pos<=m)  Update(pos,val,lson);
35     else Update(pos,val,rson);
36     PushUp(rt);
37 }
38
39 int Query(int L,int R,int l,int r,int rt)
40 {
41     if(L<=l&&r<=R){
42         return MAX[rt];
43     }
44     int m=(l+r)>>1;
45     int res=0;
46     if(L<=m) res=max(res,Query(L,R,lson));
47     if(R>m) res=max(res,Query(L,R,rson));
48     return res;
49 }
50
51 int main()
52 {
53     while(scanf("%d%d",&N,&M)==2)
54     {
55         for (int i=1;i<=N;i++) scanf("%d",&A[i]);
56         Build(1,N,1);
57         int a,b;
58         char op;
59         for (int i=0;i<M;i++){
60             scanf(" %c",&op);
61             scanf("%d%d",&a,&b);
62             if(op=='Q'){
63                 int ans=Query(a,b,1,N,1);
64                 printf("%d\n",ans);
65             }else
66             {
67                 Update(a,b,1,N,1);
68             }
69         }
70     }
71     return 0;
72 }

hdu 1754

HDU 1394 线段树功能:update:单点增减 query:区间求和

这道题求最小逆序数。线段树怎么求逆序数呢?就是依次读入序列时,把读入的值加入线段树,每次查询时,就看比这个值大的区间有多少个元素,就是这个数对应逆序数的个数了。而这道题不仅让求逆序数,而且序列还可以一位一位向后移,要求最少的逆序数。既然刚开始读入序列已经知道了一个逆序数个数,那么后面考虑的就是向后移动一个数字会对当前结果造成什么影响。比如说序列是:1 3 6 9 0 8 5 7 4 2 当我把1放在最后面时,只需考虑有关1的逆序数增减。可以发现,对于题目要求的n个数的序列,每次往后移动一个数a[i],也就是a[i]放在了最后(这里理解好就懂了,我想了挺长时间),增加的逆序数个数为n-a[i]-1(就是比a[i]大的数的个数),减少的逆序数个数为a[i](自然就是不大于a[i]的数)。所以每移动一次,逆序数就变为cnt+=n-a[i]-1-a[i].

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 using namespace std;
 7 const int maxn=5005;
 8 int a[maxn],sum[maxn<<2];
 9 int n;
10
11 void PushUp(int rt)
12 {
13     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
14 }
15
16 void Build(int l,int r,int rt)
17 {
18     sum[rt]=0;
19     if(l==r) return;
20     int m=(l+r)>>1;
21     Build(lson);
22     Build(rson);
23 }
24
25 void Update(int pos,int l,int r,int rt)
26 {
27     if(l==r){
28         sum[rt]++;
29         return;
30     }
31     int m=(l+r)>>1;
32     if(pos<=m) Update(pos,lson);
33     else Update(pos,rson);
34     PushUp(rt);
35 }
36
37 int Query(int L,int R,int l,int r,int rt)
38 {
39     if(L<=l&&r<=R){
40         return sum[rt];
41     }
42     int res=0;
43     int m=(l+r)>>1;
44     if(L<=m) res+=Query(L,R,lson);
45     if(R>m) res+=Query(L,R,rson);
46     return res;
47 }
48
49 int main()
50 {
51     while(scanf("%d",&n)==1)
52     {
53         Build(0,n-1,1);
54         int cnt=0;
55         for (int i=0;i<n;i++)
56         {
57             cin>>a[i];
58             cnt+=Query(a[i],n-1,0,n-1,1);
59             Update(a[i],0,n-1,1);
60         }
61         int ans=cnt;
62         for (int i=0;i<n;i++){
63             cnt+=n-a[i]-1-a[i];
64             ans=min(ans,cnt);
65         }
66         cout<<ans<<endl;
67     }
68     return 0;
69 }

hdu 1394

HDU 2795 线段树功能:query:区间求最大值的位置(直接把update的操作在query里做了)

这道题把h当作原来A[],相当于每一层,开始赋值都是w。所以这里也用MAX[]数组替代sum[]数组维护区间的最大值,因为层数小,能够贴的位置先贴。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 using namespace std;
 7 const int maxn=200005;
 8 int MAX[maxn<<2];
 9 int n,h,w;
10
11 void PushUp(int rt)
12 {
13     MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
14 }
15
16 void Build (int l,int r,int rt)
17 {
18     MAX[rt]=w;
19     if(l==r) return;
20     int m=(l+r)>>1;
21     Build(lson);
22     Build(rson);
23 }
24
25 int Query(int val,int l,int r,int rt)
26 {
27     if(l==r){
28         MAX[rt]-=val;
29         return l;
30     }
31     int m=(l+r)>>1;
32     int res=(MAX[rt<<1]>=val)?Query(val,lson):Query(val,rson);
33     PushUp(rt);
34     return res;
35 }
36
37 int main()
38 {
39     while(scanf("%d%d%d",&h,&w,&n)==3)
40     {
41         if(h>n) h=n;
42         Build(1,h,1);
43         int x;
44         for (int i=0;i<n;i++)
45         {
46             scanf("%d",&x);
47             if(MAX[1]<x)
48                 printf("-1\n");
49             else
50                 printf("%d\n",Query(x,1,h,1));
51         }
52     }
53     return 0;
54 }

hdu 2795

参考资料:

【1】NotOnlySuccess 【完全版】线段树

【2】http://blog.csdn.net/zearot/article/details/52280189

【3】http://blog.csdn.net/zearot/article/details/48299459

【4】http://www.cnblogs.com/xiaoyao24256/p/6590885.html

转载于:https://www.cnblogs.com/zxhyxiao/p/7290153.html

线段树总结(一)【数据结构】相关推荐

  1. 数据结构之线段树入门(单点更新区间查询)

    线段树是学习数据结构必须学习的一种数据结构,在ACM,蓝桥等比赛中是经常出现的.利用线段树解题,会使得题目简单易理解.而且线段树是数据结构中比较基础而且用的很多的一种. 线段树定义 线段树是一种二叉搜 ...

  2. (转)线段树的区间更新

    原文地址:http://blog.csdn.net/zip_fan/article/details/46775633 写的很好,昨天刚刚开始写线段树,有些地方还不是很明白,看了这篇博文,学会了数组形式 ...

  3. 截部分陈宏对用线段树解矩形并的轮廓(picture 问题的深入讨论)

    Picture问题的深入讨论 基于对数据结构选择的进一步分析,我们来重新考虑一下Picture问题的数据结构的选择,即采用树形结构来描述一组超元线段的状态. 一.线段树 受到累计扫描过程的启发,一组超 ...

  4. 线段树的创建插入查找删除

    一.线段树基本概念 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点.     对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间 ...

  5. 数据结构线段树介绍与笔试算法题-LeetCode 307. Range Sum Query - Mutable--Java解法

    此文首发于我的个人博客:zhang0peter的个人博客 LeetCode题解文章分类:LeetCode题解文章集合 LeetCode 所有题目总结:LeetCode 所有题目总结 线段树(Segme ...

  6. 307. Range Sum Query - Mutable | 307. 区域和检索 - 数组可修改(数据结构:线段树,图文详解)

    题目 https://leetcode.com/problems/range-sum-query-mutable/ 吐槽官方题解 这题的 英文版官方题解,配图和代码不一致,而且描述不清:力扣国内版题解 ...

  7. 数据结构(终极线段树篇)

    数据结构(终极线段树篇) 摘要: 问题的提出:如何解决多样化的区间操作问题? solve:线段树!!! 关键字: 线段树,可持久化线段树,权值线段树,线段树森林,动态开点线段树,区间操作,线段树应用. ...

  8. 【DP】【线段树】基站选址(luogu 2605/金牌导航 数据结构优化DP-2)

    正题 luogu 2605 金牌导航 数据结构优化DP-2 题目大意 有若干个村庄在一条直线上,距离第一个村庄did_idi​,在该村庄建立基站要花费cic_ici​,如果在离该村不大于sis_isi ...

  9. 简单的数据结构题(多项式、拉格朗日插值、线段树)

    简单的数据结构题 首先考虑计算要求的式子,不妨设l=1,r=nl=1,r=nl=1,r=n. ∑i=1naik∏j≠i1−aiajai−aj\sum_{i=1}^{n}a_i^k\prod_{j\n ...

最新文章

  1. NT系统DOS网络命令记录
  2. 在多个的共享ndk项目之间共享模块
  3. Python从零开始系列连载(11)——Python的基本运算和表达式(中二)
  4. MySQL的存储引擎InnoDB,B+Tree数据结构索引的实现原理图(聚簇索引/聚集索引)
  5. access 如何使用dolby_用Access开发《生产管理系统》
  6. 拓端tecdat|R语言Gibbs抽样的贝叶斯简单线性回归仿真分析
  7. c语言程序设计支持win10,win tc 64位下载-wintc C语言编译器64位下载 1.9.1 win10兼容版 - 河东下载站...
  8. 通过DLL文件实现函数共有及通过调用_stdcall来减少程序文件的大小
  9. Opencv3.0-python: 编译报错color.cpp:7456: error: (-215) scn == 3
  10. Apple ID 登录
  11. 软件工程的10个知识领域
  12. 20201024腾格尔沙漠徒步
  13. webbench源码阅读
  14. 师生使用计算机不得,师生文明上网行为规范
  15. MediaPlayer基础
  16. 如何让百度搜索收录自己的Hexo博客文章
  17. 《动手学深度学习》(四) -- LeNet、AlexNet、VGG、NiN、GoogLeNet、ResNet、DenseNet 实现
  18. C语言实现商品销售系统
  19. c语言程序设计数学电压表,单片机课程设计-数字电压表的设计.doc
  20. 高校学生工作信息系统研究

热门文章

  1. php如何转换类型,PHP数据类型转换
  2. 系统优化怎么做-Tomcat优化
  3. was连接oracle rac集群,Oracle集群(RAC)及 jdbc 联接双机数据库
  4. hadoop 文本统计一个字符的个数_使用hadoop统计多个文本中每个单词数目
  5. ubuntu笔记:查看Ubuntu的包依赖关系
  6. mysql pdo使用存储过程_PDO调用存储过程的问题
  7. python的全局变量能暂存数据吗_Python 中的全局变量 局部变量
  8. 2015 计算机考研大纲,2015年考研计算机大纲详解:操作系统
  9. html5显示字幕信息,HTML5 Placeholder实现input背景文字提示效果
  10. python中词云图怎样变成特殊图案_如何利用python画出一个多变的词云图?(1)...