hdu1754 I hate it线段树模板 区间最值查询
题目链接:这道题是线段树,树状数组最基础的问题
两种分类方式:按照更新对象和查询对象
单点更新,区间查询;
区间更新,单点查询;
按照整体维护的对象:
维护前缀和;
维护区间最值.
线段树模板代码
#include<iostream> #include<string.h> #include<stdio.h> #include<math.h> #include<algorithm> using namespace std; #define re(i,n) for(int i=0;i<n;i++) typedef long long ll; const int maxn = 2 * 1e5 + 7; #define lson(x) x<<1,f,mid #define rson(x) x<<1|1,mid+1,t int n, m; int tr[maxn << 2]; int x, y; int ans; void build(int r, int f, int t){if (f == t){scanf("%d", &tr[r]);return;}int mid = (f + t) >> 1;build(lson(r)),build(rson(r));tr[r] = max(tr[r << 1], tr[r << 1 | 1]); } void query(int r, int f, int t){if (f >= x&&t <= y){ans = max(ans, tr[r]);return;}int mid = (f + t) >> 1;if (x <= mid)query(lson(r));if (y > mid)query(rson(r)); } void update(int r, int f, int t){if (f == t){tr[r] = y;return;}int mid = (f + t) >> 1;if (x<= mid)update(lson(r));else update(rson(r));tr[r] = max(tr[r << 1], tr[r << 1 | 1]); } int main(){//freopen("in.txt", "r", stdin);while (cin >> n >> m){ build(1, 1, n); while (m--){char op[2]; scanf("%s%d%d", op,&x,&y); if (op[0] == 'Q'){if (x > y)swap(x, y);ans = -1;query(1, 1, n);printf("%d\n", ans);}else{update(1, 1, n);}}}return 0; }
树状数组区间最值模板代码
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; const int maxn = 2*1e5+7; typedef long long ll; #define re(i,n) for(int i=0;i<n;i++) int a[maxn], c[maxn]; /* a里面存放本值,c里面维护最值 */ int n, q; int lowbit(int x){return x&-x; } void redo(int i){c[i] = i;for (int j = 1; j < lowbit(i); j <<= 1)if (a[c[i - j]]>a[c[i]])c[i] = c[i - j]; } void init(){for (int i = 1; i <= n; i++){redo(i);} } void update(int x, int y){ bool big = y > a[x];a[x] = y;int i = x;if (big){/*这个地方如果错写成a[c[i]]<y就会导致无法传递上去,因为一开始时就是a[c[i]]==y.*/while (i<=n&&a[c[i]] <= y)c[i] = x, i += lowbit(i);}else{ while (i<=n&&c[i] == x)redo(i), i += lowbit(i);} } int query(int l, int r){int ans = a[r];while (l<=r){ while (r - lowbit(r) >= l){ans = max(a[c[r]], ans);r -= lowbit(r);}ans = max(a[r], ans);//根节点r--;//向下走一步 }return ans; } int main(){freopen("in.txt", "r", stdin);while (scanf("%d%d", &n, &q) == 2){re(i, n)scanf("%d", &a[i + 1]);init();int qi = 0;while (q--){char op[2]; int x, y;qi++;scanf("%s%d%d", &op, &x, &y);if (op[0] == 'U'){update(x, y);}else{int ans = query(x, y);printf("%d\n", ans);}}}return 0; }
复杂度是O(lgn*lgn).这道题数据好像有点弱,因为错误的代码也能过这道题.
zwk线段树模板
zwk线段树巧妙之处在于开区间写法,对于长度为N的线段,初始化时,共N+2片叶子:1和N+2空着,2~N+1才是本体,是实实在在的数据.张昆玮说了:如果有1023个数据,那就要有2048片叶子.空间要开到(N+2)*4才行.虽然费了点空间,但编程简洁了.
根节点(1号结点)和每层的第一个节点和最后一个节点是哨兵节点,永远都不会访问到它们.它们的存在只是方便编程.老子曰:将欲取之,必先予之.一言以蔽之,就是两端边界处的节点都是哨兵节点,这是开区间方便编程导致的.
那么闭区间写法行不行呢?对于长度为N的线段,1~N全部用上,查询时闭区间可以转换成开区间.如果有1023个数,那就只需要开辟1024片叶子的树状数组.开区间=闭区间-两个端点.若无论如何都更新两个端点,那就会导致更新的东西有点靠下,这对于结果并没什么影响.需要注意l==r的情形.
zwk开区间写法
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2 * 1e5 + 7; 6 typedef long long ll; 7 #define re(i,n) for(int i=0;i<n;i++) 8 int a[maxn << 2]; 9 int n, q, sz; 10 void update(int x, int v){ 11 x += sz; 12 a[x] = v; 13 while (x >1){ 14 x >>= 1; 15 a[x] = max(a[x << 1], a[x << 1 | 1]); 16 } 17 } 18 int query(int l, int r){ 19 l += sz - 1, r += sz + 1; 20 int ans =0; 21 while (l^r ^ 1){//当两人不是兄弟时 22 if (~l & 1){ 23 ans = max(ans, a[l ^ 1]); 24 } 25 if (r & 1){ 26 ans = max(ans, a[r ^ 1]); 27 } 28 l >>= 1, r >>= 1; 29 } 30 return ans; 31 } 32 int main(){ 33 //freopen("in.txt", "r", stdin); 34 while (scanf("%d%d", &n, &q) == 2){ 35 sz = 1; while (sz < n+2)sz <<= 1; 36 re(i, n){ 37 scanf("%d", &a[i + sz+1]); 38 } 39 for (int i = n; i <= (sz << 1); i++)a[i + sz+1] = 0; 40 for (int i = sz - 1; i>0; i--){ 41 a[i] = max(a[i << 1], a[i << 1 | 1]); 42 } 43 while (q--){ 44 char op[2]; int x, y; 45 scanf("%s%d%d", op, &x, &y); 46 if (op[0] == 'U'){ 47 update(x, y); 48 } 49 else{ 50 int ans = query(x, y); 51 printf("%d\n", ans); 52 } 53 } 54 } 55 return 0; 56 }
zwk闭区间写法:下面的代码有bug.能过题.
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2 * 1e5 + 7; 6 typedef long long ll; 7 #define re(i,n) for(int i=0;i<n;i++) 8 int a[maxn << 2]; 9 int n, q, sz; 10 void update(int x, int v){ 11 x += sz-1; 12 a[x] = v; 13 while (x >1){ 14 x >>= 1; 15 a[x] = max(a[x << 1], a[x << 1 | 1]); 16 } 17 } 18 int query(int l, int r){ 19 l += sz - 1, r += sz - 1; 20 int ans =max(a[l],a[r]); //查询时先把两个端点给处理掉,就相当于开区间了. 21 /* 22 这个地方的不同决定了两种写法,我觉得没有必要开区间.闭区间预处理一下就很好. 23 这个地方如果l==r,就会产生死循环.但是我这么写,这道题却过了.*/ 24 while (l^r ^ 1){//当两人不是兄弟时 25 if (~l & 1){ 26 ans = max(ans, a[l ^ 1]); 27 } 28 if (r & 1){ 29 ans = max(ans, a[r ^ 1]); 30 } 31 l >>= 1, r >>= 1; 32 } 33 return ans; 34 } 35 void init(){ 36 sz = 1; while (sz < n)sz <<= 1; 37 re(i, n){ 38 scanf("%d", &a[i + sz]);//在1~N之间存放数据 39 } 40 for (int i = n; i <= (sz << 1); i++)a[i + sz ] = 0; 41 for (int i = sz - 1; i>0; i--){ 42 a[i] = max(a[i << 1], a[i << 1 | 1]); 43 } 44 } 45 int main(){ 46 freopen("in.txt", "r", stdin); 47 while (scanf("%d%d", &n, &q) == 2){ 48 init(); 49 while (q--){ 50 char op[2]; int x, y; 51 scanf("%s%d%d", op, &x, &y); 52 if (op[0] == 'U'){ 53 update(x, y); 54 } 55 else{ 56 int ans = query(x, y); 57 printf("%d\n", ans); 58 } 59 } 60 } 61 return 0; 62 }
转载于:https://www.cnblogs.com/weiyinfu/p/4854396.html
hdu1754 I hate it线段树模板 区间最值查询相关推荐
- BZOJ-4811: [Ynoi2017]由乃的OJ (树链剖分 线段树维护区间操作值 好题)
4811: [Ynoi2017]由乃的OJ Time Limit: 6 Sec Memory Limit: 256 MB Submit: 366 Solved: 118 [Submit][Stat ...
- 【HDU - 1698】 Just a Hook(线段树模板 区间覆盖更新(laz标记) + 区间和查询 )
题干: In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroe ...
- POJ——3624 Balanced Lineup(线段树入门——区间最值问题)
原题链接:http://poj.org/problem?id=3264 每天挤奶时,农夫John的N头奶牛(1≤N≤50,000头)总是按照相同的顺序排列.一天,农夫约翰决定和几头牛组织一场极限飞盘游 ...
- 【POJ - 3468 】 A Simple Problem with Integers (线段树模板 区间更新 + 区间和查询)(不能树状数组或差分数组)
题干: You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o ...
- 【HDU - 3974】 Assign the task (dfs序 + 线段树维护 区间更新+ 单点查询)
题干: There is a company that has N employees(numbered from 1 to N),every employee in the company has ...
- [SCOI2007]降雨量 线段树和区间最值(RMQ)问题
题目链接P2471 [SCOI2007]降雨量 听说博客观看效果更佳 这道题是比较经典的 RMQRMQRMQ 问题,找到X和Y年间的最值来进行判断真假 , 用线段树维护是比较简单好写的.然而这只 ...
- 线段树(区间修改)模板题 Luogu 2357 守墓人
众所周知,线段树可以在O( log n)的时间内进行很多修改和查询的操作,应用很广. 线段树,顾名思义,是一个二叉树,但是每个节点,存的不是不是"数",而是一个"区间&q ...
- 线段树模板题3:区间染色问题
1.3线段树模板题3:区间染色问题 在DotA游戏中,帕吉的肉钩实际上是大多数英雄中最恐怖的东西.挂钩由长度相同的几个连续的金属棍组成. 现在,帕吉(Pudge)希望对挂接进行一些操作. 让我们将钩子 ...
- CodeForces - 1401 F Reverse and Swap(线段树, 区间翻转, 区间交换,清晰易懂)
CodeForces - 1401 F Reverse and Swap(线段树, 区间翻转, 区间交换) 首先一共有四个操作,第一个和第四个都是线段树的基本操作,直接用线段树实现. 第 ...
最新文章
- Excel超级链接方式应用技巧
- 44. 源代码解读-RocketMQ-架构
- rootfs 制作ubuntu_为n1制作aarcm64/arm64 ubuntu rootfs系统
- winCE改变字库方法(WINCE字库更新)
- Spring 之注解事务 @Transactional
- Intellij IDEA中Mybatis Mapper自动注入警告的6种解决方案
- [有限元] Ansys Workbench Mechanical 中的应力应变显示类型的文档翻译
- 未来互联网还有哪些值得关注的趋势?
- git不能上传空目录和设备文件
- adb—fastboot—Download Honor 4C ClockworkMod (Cofface) Custom Recovery
- 聚宽数据(JQData)本地化解决方案:基于MongoDB
- 这是我见过最好的唐诗,而且通俗易懂2
- “心脏滴血”漏洞复现
- 基于Huggingface的预训练语言模型分类体系及实战
- ios 基于CAEmitterLayer的雪花,烟花,火焰,爱心等效果demo
- Latex标题页的上标和脚注
- UG CAM 开发获取工序导航器当前选择的操作、程序组、几何体、刀具方法,获得名字并修改名字
- 华为鸿蒙os尝鲜,华为鸿蒙os尝鲜版
- 跨境电商「独角兽」融资40亿+,这家公司是怎么做增长的?
- c# iot .net 树莓派读取土壤湿度感应器 代码实例
热门文章
- [考试反思]0813NOIP模拟测试20
- net.sf.json.JSONObject处理 null 字符串的一些坑
- angularjs -- 页面模板清除
- openstack镜像制作详解
- 7.1 XHTML的规范化
- Frameset使用教程
- [已解决问题] Could not find class XXX referenced from method XXX.YYY
- 一步步构建大型网站架构(转载)
- java一次性查询几十万,几百万数据解决办法
- 免费的中文OCR软件