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 ...
随机推荐
- pycharm专业版激活破解(亲测有效)
完成破解步骤,亲测有效! 1.打开路径,修改hosts文件:C:\Windows\System32\drivers\etc 找到hosts文件打开 最后一行添加这行代码: 0.0.0.0 acco ...
- Yuchuan_Linux_C 编程之三 静态库的制作和使用
一.整体大纲 二.静态库的制作 1)命名规则 lib + 库的名字 + .a 例如:libyuchuan.a2)制作步骤: 1). 生成对应的.o文件 -- ...
- 检测js对象是不是数组类型?
面试时候被人问如何检测一个未知变量是不是数组类型,丢脸啊,老祖宗的脸都丢没了,这都不会,回家啃书本去吧!!! var a = [];方法一:Array.isArray([]) //true type ...
- java后台生成并下载二维码
这个功能在项目开发中是很基础的,平时用到的也很多,这里简单记录一下,以便以后使用的时候参考 前提业务要求:前台页面展示数据,有下载按钮,点击下载,下载对应数据的二维码. 首先,在pom.xml文件中添 ...
- HDFS NameNode详解
1. namenode介绍 namenode管理文件系统的命名空间.它维护着文件系统树及整棵树内所有的文件和目录.这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件fsimage和编辑日志文 ...
- 正则匹配电话号码demo
public static String doFilterTelnum(String sParam) { String result = sParam; if (sParam.length() < ...
- Python习题集(三)
每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 写一个小程序:控制 ...
- defer 链如何被遍历
去年开始写文章的第一篇就是关于 defer,名字比较文艺:<Golang 之轻松化解 defer 的温柔陷阱>,还被吐槽了.因为这篇文章,到<Go 夜读>讲了一期.不过当时纯粹 ...
- iOS开发:判断iPhone是否是刘海屏iPhoneX、iPhoneXR、iPhoneXs、iPhoneXs Max等
保证能判断,呕心沥血,不行切JIJI 方法一 Objective-C // iPhoneX.iPhoneXR.iPhoneXs.iPhoneXs Max等 // 判断刘海屏,返回YES表示是刘海屏 - ...
- Python之split()函数
在Python的高级特性里有切片(Slice)操作符,可以对字符串进行截取.Python还提供split()函数可以将一个字符串分裂成多个字符串组成的列表. split()的语法挺简单的: str.s ...





