HDU1166(线段树 +更新单点,求区间总和)、HDU1754(线段树 + 更新单点,求区间最大值)
线段树简单应用
- HDU1166:题目描述
线段树 +更新单点,求区间总和
代码如下(递归版)
#include<iostream>
#include<string>
using namespace std;
#define MAXN 50005
#define ls l,m,pos << 1
#define rs m+1,r,pos << 1 | 1
int node[MAXN],Sum[MAXN << 2],Add[MAXN << 2];
//上推更新信息、建树
void Push_up(int pos)
{
Sum[pos] = Sum[pos << 1] + Sum[pos << 1 | 1];
}
void Build(int l, int r, int pos)
{
if(l == r)
{
Sum[pos] = node[l];
return;
}
//左右递归区间
int m = (l + r) >> 1;
Build(ls);
Build(rs);
//更新信息
Push_up(pos);
}
//点的修改
void Update_point(int l, int r, int pos, int x, int c)
{
if(l == r)
{
Sum[pos] += c;
return;
}
//看下标x 是在左子区间,还是在有子区间
int m = (l + r) >> 1;
if(x <= m) Update_point(ls, x, c);
else Update_point(rs, x, c);
//回溯的时候从下往上更新 Sum
Push_up(pos);
}
//下推做标记、区间的修改
void Push_down(int ln, int rn, int pos)
{
if(Add[pos])
{
//向下标记子区间
Add[pos << 1] += Add[pos];
Add[pos << 1 | 1] += Add[pos];
//更新sum值
Sum[pos << 1] += Add[pos] * ln;
Sum[pos << 1 | 1] += Add[pos] * rn;
//解除当前的标记
Add[pos] = 0;
}
}
void Update_area(int l, int r, int pos, int s, int e, int c)
{
if(s <= l && r <= e)
{
Sum[pos] += (r - l + 1) * c;
Add[pos] += c;
return;
}
//对左右区间进行讨论
int m = (l + r) >> 1;
//先下推标记,为更新本节点的 Sum 做准备
Push_down(m - l + 1, r - m, pos);
if(s <= m) Update_area(ls, s, e, c);
if(e > m) Update_area(rs, s, e, c);
//上推更新当前的Sum,因为可能子Sum已经改变
Push_up(pos);
}
int Query(int l, int r, int pos, int s, int e)
{
if(s <= l && r <= e)
{
return Sum[pos];
}
//左右区间进行讨论,积累答案
int m = (l + r) >> 1;
Push_down(m - l + 1, r - m, pos); //⚠当前的这个下推语句在这个一次查询的时候不会被执行(由于查询区间的限制),但在以后的查询中 起着更新 子Sum的作用(由于以前的某个/些 子区间没有被执行,所以当来到 这个区间的到时候我们要的是 已经更新过的 子区间Sum)
int ans = 0;
if(s <= m) ans += Query(ls, s, e);
if(e > m) ans += Query(rs, s, e);
return ans;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr);
//freopen("T.txt","r",stdin);
string s1 = "Add";
string s2 = "Sub";
string s3 = "Query";
string s4 = "End";
string s;
int t, Case = 1;
cin >> t;
while(t --)
{
cout << "Case "<<Case ++<<":" << endl;
int n;
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> node[i];
Build(1, n, 1);
while(cin >> s && s != s4)
{
int a,b;
cin >> a >> b;
if(s == s1)
Update_point(1, n, 1, a, b);
else if(s == s2)
Update_point(1, n, 1, a,-b);
else
cout << Query(1, n, 1, a, b) << endl;
}
}
return 0;
}
代码如下(非递归版)
#include<iostream>
using namespace std;
#define MAXN 50005
#define ls l,m,pos << 1
#define rs m+1,r,pos << 1 | 1
int node[MAXN],Sum[MAXN << 2],Add[MAXN << 2];
int N,n;
//建立线段树
void Build(int n)
{
//找n接近的 2 的次方数
N = 1; while(N < n + 2) N <<= 1;
//更新叶节点
for(int i = 1; i <= n; i ++) Sum[i + N] = node[i]; //存储叶节点的下标 + N == 叶节点位于树中的下标 == 存储数据的 node 数组中的下标
//更新非叶节点
for(int i = N - 1; i > 0; i --)
{
//更新所有非叶节点的统计信息
Sum[i] = Sum[i << 1] + Sum[i << 1 | 1];
//清空所有非叶节点的标记
Add[i] = 0;
}
}
//点的修改
void Update_point(int x, int c)
{
for(int pos = N + x; pos; pos >>= 1)
{
Sum[pos] += c;
}
}
//没有标记下的区间查询
int Query(int s, int e)
{
int ans = 0;
for(int L = N + s - 1,R = N + e + 1; L ^ R ^ 1; L >>= 1, R >>= 1)
{
if(~ L & 1) ans += Sum[L ^ 1];
if( R & 1) ans += Sum[R ^ 1];
}
return ans;
}
//区间修改
void Update_area(int s, int e, int c)
{
int L,R,Ln = 0,Rn = 0,x = 1;
for(L = N + s -1, R = N + e + 1; L ^ R ^ 1; L >>= 1, R >>= 1, x <<= 1)
{
//更新Sum
Sum[L] += c * Ln;
Sum[R] += c * Rn;
//处理Add标记
if(~ L & 1) Add[L ^ 1] += c,Sum[L ^ 1] += c * x,Ln += x;
if( R & 1) Add[R & 1] += c,Sum[R & 1] += c & x,Rn += x;
}
//更新上层的Sum
for( ; L; L >>= 1, R >>= 1)
{
Sum[L] += c * Ln;
Sum[R] += c * Rn;
}
}
//区间查询
int Query_area(int s, int e)
{
int ans = 0;
int L,R,Ln = 0,Rn = 0,x = 1;
for(L = N + s - 1, R = N + e + 1; L ^ R ^ 1; L >>= 1, R >>= 1, x <<= 1)
{
//如果当前节点有标记(说明该节点的 子节点,子子节点 。。。。 是没有加上标记值的)
ans += Add[L] * Ln;
ans += Add[R] * Rn;
//如果该节点是左子节点的左子树 或 右子节点的右子树
if(~ L & 1) ans += Sum[L ^ 1], Ln += x;
if( R & 1) ans += Sum[R ^ 1], Rn += x;
}
//处理上层的标记
for( ; L; L >>= 1, R >>= 1)
{
ans += Add[L] * Ln;
ans += Add[R] * Rn;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr);
//freopen("T.txt","r",stdin);
string s1 = "Add";
string s2 = "Sub";
string s3 = "Query";
string s4 = "End";
string s;
int t, Case = 1;
cin >> t;
while(t --)
{
cout << "Case "<<Case ++<<":" << endl;
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> node[i];
Build(n);
while(cin >> s && s != s4)
{
int a,b;
cin >> a >> b;
if(s == s1)
Update_point(a, b);
else if(s == s2)
Update_point(a,-b);
else
cout << Query_area(a, b) << endl;
}
}
return 0;
}
- HDU1754: 题目描述
线段树 +更新单点,求区间最大值!!!
代码如下
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define ls l,m,pos << 1
#define rs m+1,r,pos << 1 | 1
int node[MAXN],Max[MAXN << 2],Add[MAXN << 2];
//向上传递更新信息、建树
void Push_up(int pos)
{
Max[pos] = max(Max[pos << 1], Max[pos << 1 | 1]);
}
void Build(int l, int r, int pos)
{
if(l == r)
{
Max[pos] = node[l];
return;
}
//分左右子区间进行讨论
int m = (l + r) >> 1;
Build(ls);
Build(rs);
Push_up(pos);
}
void Update_point(int l, int r, int pos, int x, int c)
{
if(l == r)
{
Max[pos] = c;
return;
}
//分左右区间进行讨论
int m = (l + r) >> 1;
if(x <= m) Update_point(ls, x, c);
else Update_point(rs, x, c);
Push_up(pos);
}
int Query(int l, int r, int pos, int s, int e)
{
if(s <= l && r <= e)
{
return Max[pos];
}
//分左右区间
int m = (l + r) >> 1;
int mx = -1;
if(s <= m) mx = max(mx, Query(ls, s, e));
if(e > m) mx = max(mx, Query(rs, s, e));
return mx;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr);
//freopen("T.txt","r",stdin);
int n,m;
while(cin >> n >> m)
{
for(int i = 1; i <= n; i ++)
cin >> node[i];
Build(1, n, 1);
char ch;
int a, b;
while(m --)
{
cin >> ch >> a >> b;
if(ch == 'Q')
cout << Query(1, n, 1, a, b) << endl;
else
Update_point(1, n, 1, a, b);
}
}
return 0;
}
代码如下(非递归版)
⚠️ 这个代码 超时了,也没想好怎么优化
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
int node[MAXN],Max[MAXN << 2];
int n,N;
//非递归线段树建树
void Build(int n)
{
//找到一个 > n + 2 的 N
N = 1; while(N < n + 2) N <<= 1;
//处理叶节点的Max问题
for(int i = 1; i <= n; i ++)
Max[N + i] = node[i];
//处理非叶节点的最大值
for(int i = N - 1; i; i --)
Max[i] = max(Max[i << 1], Max[i << 1 | 1]);
}
//更新某个节点的值
void Update_point(int x, int c)
{
Max[N + x] = c;
int i = N + x;
for(i >>= 1; i; i >>= 1)
{
Max[i] = max(Max[i << 1], Max[i << 1 | 1]);
}
}
int Query(int s, int e)
{
int L,R,mx = -1;
for(L = N + s - 1,R = N + e + 1; L ^ R ^ 1; L >>= 1, R >>= 1)
{
if(~ L & 1) mx = max(mx, Max[L ^ 1]);
if( R & 1) mx = max(mx, Max[R ^ 1]);
}
return mx;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr);
//freopen("T.txt","r",stdin);
int n,m;
while(cin >> n >> m)
{
for(int i = 1; i <= n; i ++)
cin >> node[i];
Build(n);
char ch;
int a, b;
while(m --)
{
cin >> ch >> a >> b;
if(ch == 'Q')
cout << Query(a, b) << endl;
else
Update_point(a, b);
}
}
return 0;
}
HDU1166(线段树 +更新单点,求区间总和)、HDU1754(线段树 + 更新单点,求区间最大值)的更多相关文章
- HDU(1166),线段树模板,单点更新,区间总和
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 第一次做线段树,帆哥的一句话,我记下来了,其实,线段树就是一种处理数据查询和更新的手段. 然后, ...
- CSU-1110 RMQ with Shifts (单点更新+区间最小值 zkw线段树)
In the traditional RMQ (Range Minimum Query) problem, we have a static array A. Then for each query ...
- HDU.1689 Just a Hook (线段树 区间替换 区间总和)
HDU.1689 Just a Hook (线段树 区间替换 区间总和) 题意分析 一开始叶子节点均为1,操作为将[L,R]区间全部替换成C,求总区间[1,N]和 线段树维护区间和 . 建树的时候初始 ...
- POJ 2528 Mayor's posters(线段树区间染色+离散化或倒序更新)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 59239 Accepted: 17157 ...
- HDU 1540 Tunnel Warfare(经典)(区间合并)【线段树】
<题目链接> 题目大意: 一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R 表示修复最后毁坏的那个单元 Q x 询问这个单元以及它周围有多少个连续的单元,如果它本身已经被 ...
- HDU 3308 LCIS (经典区间合并)【线段树】
<题目链接> 题目大意: 给你一段序列,对其进行两种操作,一是修改某个序号的点的值:二是查询某个区间的LCIS(最长上升子序列). 解题分析: 线段树区间合并的典型例题,用求某个区间的LC ...
- HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化
题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...
- 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)
Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...
- HDU1542 Atlantis —— 求矩形面积并 线段树 + 扫描线 + 离散化
题目链接:https://vjudge.net/problem/HDU-1542 There are several ancient Greek texts that contain descript ...
随机推荐
- PYTHON 第二天学习记录
- 获取的ajax方法return的返回值的问题解析
今天刚上班就偶遇关于获取Ajax方法return的返回值的问题,这里小记一下. 在使用jquery中,如果获取不到ajax返回值,原因有二: 一.ajax未使用同步 ajax未使用同步,导致数据未加载 ...
- python之嵌套 闭包 装饰器 global、nonlocal关键字
嵌套: 在函数的内部定义函数闭包: 符合开放封闭原则:在不修改源代码与调用方式的情况下为函数添加新功能 # global 将局部变量变成全局变量 num = 100 def fn1(): globa ...
- 关于vue-cli3打包时遇到Cannot assign to read only property 'exports' of object '#<Object>'问题的解决方法。
vue-cli3打包时遇到Cannot assign to read only property 'exports' of object '#<Object>'问题的解决方法. 大致是说, ...
- 深入学习用 Go 编写 HTTP 服务器
Go是一门通用的编程语言,想要学习 Go 语言的 Web 开发,就必须知道如何用 Go 启动一个 HTTP 服务器用于接收和响应来自客户端的 HTTP 请求.用 Go实现一个http server非常 ...
- Simulink仿真入门到精通(十七) Simulink代码生成技术详解
17.1 基于模型的设计 基于模型设计是一种流程,较之传统软件开发流程而言,使开发者能够更快捷.更高效地进行开发.适用范围包括汽车电子信号处理.控制系统.通信行业和半导体行业. V字模型开发流程整体描 ...
- 每天都在用 Map,这些核心技术你知道吗?
本篇文章站在多线程并发安全角度,带你了解多线程并发使用 HashMap 将会引发的问题,深入学习 ConcurrentHashMap ,带你彻底掌握这些核心技术. 全文摘要: HashMap 核心技术 ...
- EPX-Studio调用Dll模块
procedure TForm1.BitBtn1Click(Sender: TObject); var REP : IExcelPanelXDisp; modulePath:string; begin ...
- Head First设计模式——原型模式和访问者模式
原型 原型模式:当创建给定类的过程很昂贵或很复杂时,就使用原型模式. 我们在进行游戏的时候游戏会动态创建怪,而怪时根据场景的不同而变化创建的,英雄自己也会创建一些随从.创建各式各样的怪兽实例,已经越来 ...
- java虚拟机学习记录(内存划分、垃圾回收、类加载等机制)
一直以来觉得虚拟机是Java最难的一部分,涉及最底层的原理,学起来难度很大,而且工作中基本上用不到这些原理,所以对这部分“敬而远之”.现如今工作五年了,从Java基础到算法.数据结构.网络.数据库.设 ...





