线段树 区间查询 单点修改

算法思想

这个算法是用于数组的查询和修改

可以高效的进行查询修改

但是会增加内存的使用

本质上是一种 空间换时间 的算法

这个算法把一串数组无限二分

直到分的只剩下一个数据

将每一段看成一个节点

这样就组成了一个树形结构

故名 线段树

代码实现

实现这个代码一共分三个步骤:

建树 查询 修改

这里先把变量含义解释一遍:

#define maxn 1000010
#define mid ((l+r)>>1)
#define li i<<1
#define ri 1+(i<<1)
/*
mid 线段中间节点的小标
li i线段的左子树
ri i线段的右子树
*/ int n,val[maxn];
/*
n 数组的长度
val 数组的值
*/ struct Node{
int l,r,sum;
}tree[maxn];
/*
tree 即这个树形结构
tree[i].l i线段的左端
tree[i].r i线段的右端
tree[i].sum i线段的所有节点的权值和
*/

建树

void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
if(l == r){
tree[i].sum = val[l];
return ;
}
build(li,l,mid);
build(ri,mid+1,r);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}

欲建树 先分步

我们只要处理好每个节点的三个值(l,r,sum)

这棵树自然也就建好了

l,r直接赋值即可

如果 if(l == r)

则说明这个节点已经无法再二分了

那么就把 \(val\) 的值直接赋给 \(sum\)

并且要记得 return ;

若 \(l != r\)

那就继续二分建子树

然后再把两个子树的值加起来即为自己的 \(sum\)

查询

int search(int i,int l,int r){
if(l <= tree[i].l && tree[i].r <= r)
return tree[i].sum;
if(tree[i].r < l || r < tree[i].l)
return 0; int ans = 0;
if(tree[li].r >= l) ans += search(li,l,r);
if(tree[ri].l <= r) ans += search(ri,l,r);
return ans;
}

这步的主要思想是能大块就返回大块的值

不能再二分给儿子线段处理

由于已经把数组分得很细

因此不存在查询边界在线段中却无法二分的情况

  • \(l <= tree[i].l\) && \(tree[i].r <= r\)

这说明线段已经完全包裹在区间内(就和第二根绿色线段一样)

直接返回这个线段的值即可

  • \(tree[i].r < l\) \(||\) \(r < tree[i].l\)

这说明线段完全不在取值区间内

那就返回0

  • \(tree[li].r >= l\)

这说明有区间一部分在左子线段上

那就二分进行搜索

然后返回搜好的值

  • \(tree[ri].l <= r\)

和上面同理

有区间一部分在右子线段上

修改

void add(int i,int dis,int k){
if(tree[i].l == tree[i].r){
tree[i].sum += k;
return ;
}
if(dis <= tree[li].r)
add(li,dis,k);
else
add(ri,dis,k);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}

修改我自身感觉和建树有点相像

就是改变一个节点的值然后再将涉及到这个节点的线段重新建树

  • \(tree[i].l == tree[i].r\)

这代表已经找到了这个节点

那就把这个点的值修改掉

  • \(dis <= tree[li].r\)

如果在线段里

那就继续找

  • \(tree[i].sum = tree[li].sum + tree[ri].sum;\)

更新线段的值

线段数 区间修改 单点查询

Code

#include<bits/stdc++.h>
#define maxn 1000010
#define mid ((l+r)>>1)
#define li i<<1
#define ri 1+(i<<1)
using namespace std; int n,val[maxn]; struct Node{
int l,r,sum;
}tree[maxn]; void Read(){
cin >> n;
for(int i = 1;i <= n;i++)cin >> val[i];
} void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
if(l == r){
tree[i].sum = val[l];
return ;
}
build(li,l,mid);
build(ri,mid+1,r);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
} int search(int i,int l,int r){
if(l <= tree[i].l && tree[i].r <= r)
return tree[i].sum;
if(tree[i].r < l || r < tree[i].l)
return 0; int ans = 0;
if(tree[li].r >= l) ans += search(li,l,r);
if(tree[ri].l <= r) ans += search(ri,l,r);
return ans;
} void add(int i,int dis,int k){
if(tree[i].l == tree[i].r){
tree[i].sum += k;
return ;
}
if(dis <= tree[li].r)
add(li,dis,k);
else
add(ri,dis,k);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
} void interaction(){
while(1){
int tot;
cin >> tot;
if(tot == 1){
int l,r;
cin >> l >> r;
cout << search(1,l,r) << endl;
} else if(tot == 2){
int dis,k;
cin >> dis >> k;
add(1,dis,k);
} else if(tot == 3){
return ;
}
}
} int main(){
cout << "query section" << endl << "change point" << endl;
Read();
build(1,1,n);
cout << "query 1" << endl << "change 2" << endl << "break 3" << endl;
interaction();
return 0;
}

[C++]线段树 区间查询 单点修改的更多相关文章

  1. hdu 1754 线段树(Max+单点修改)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  2. hdu 1166 线段树(sum+单点修改)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  3. I Hate It:线段树:单点修改+区间查询

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  4. poj3171 Cleaning Shifts【线段树(单点修改区间查询)】【DP】

    Cleaning Shifts Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4422   Accepted: 1482 D ...

  5. HZAU 1207 Candies(线段树区间查询 区间修改)

    [题目链接]http://acm.hzau.edu.cn/problem.php?id=1207 [题意]给你一个字符串,然后两种操作:1,将区间L,R更新为A或者B,2,询问区间L,R最长的连续的B ...

  6. 【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

    hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. #include<iostream> #include<cs ...

  7. HDU - 1166 - 敌兵布阵 线段树的单点修改,区间求和

    #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...

  8. 线段树 区间查询区间修改 poj 3468

    #include<cstdio> #include<iostream> #include<algorithm> #include<string.h> u ...

  9. hdu1754线段树的单点更新区间查询

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  10. HDU 1754 I Hate It(线段树区间查询,单点更新)

    描述 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老 ...

随机推荐

  1. Cesium 概述 (二) 空间数据可视化

    https://blog.csdn.net/happyduoduo1/article/details/51865811/

  2. 加密解决HTTP协议带来的安全问题

    HTTP协议默认是采取明文传输的,容易被中间人窃听.拦截.篡改,存在安全隐患. 常见提高安全性的方法是对通信内容进行加密,再进行传输,常见的加密方式有 不可逆加密:单向散列函数 可逆加密:对称加密.非 ...

  3. WindowsServer安装sshd服务

    系统版本:Windows Server 2016(有桌面) 网上有不少教程是用powershell在线安装,实测在server 2016上不行,但在Windows 10测试可行,不知道什么情况,所以改 ...

  4. xss-labs靶场

    在线XSS-labs靶场:https://xssaq.com/yx/ 靶场搭建 靶场是直接使用docker搭建的 docker pull vulfocus/xss-labs 启动靶场 docker r ...

  5. IE浏览器不支持TextDecoder()的问题

    IE浏览器不支持TextDecoder()方法,因此在进行Arrbuffer转string或中文时,出现未定义的错误.通过网上查找方法,可以通过引用第三方库进行解决. github地址:https:/ ...

  6. 表格JS实现在线Excel的附件上传与下载

    摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 在本地使用Excel时,经常会有需要在Excel中添加一 ...

  7. [远程Call]32位远程多参数带返回调用

    [远程Call]32位远程多参数带返回调用 引子 在Windows上可以使用CreateRemoteThread实现远程Call,但是有不带返回值且只能传递一个参数的限制. 解决思路 将多个参数利用V ...

  8. P3378 【模板】二叉堆

    [洛谷]P3378 [模板]堆 方法一 手写堆 最小堆插入 从新增的最后一个结点的父结点开始,用要插入元素向下过滤上层结点(相当于要插入的元素向上渗透) void siftdown(int i) // ...

  9. 1Nginx基础及编译安装

    1Nginx基础 1.Nginx概述 Nginx 功能介绍 Nginx(发音为"engine-x")是一个开源的高性能 HTTP和反向代理服务器.它具有以下功能: 1.静态文件服务 ...

  10. 论文解读(AdSPT)《Adversarial Soft Prompt Tuning for Cross-Domain Sentiment Analysis》

    Note:[ wechat:Y466551 | 可加勿骚扰,付费咨询 ] 论文信息 论文标题:Adversarial Soft Prompt Tuning for Cross-Domain Senti ...