当前位置: 首页 > news >正文

教育部高等学校建设中心网站免费推广网址

教育部高等学校建设中心网站,免费推广网址,广西和住房城乡建设厅网站首页,南城微信网站建设今天我来学习线段树 首先它是树有着树的结构,线段树由于本身是专门用来处理区间问题的 它的作用可以处理区间的问题拥有更快的速度. 对于每一个子节点而言,都表示整个序列中的一段子区间;对于每个叶子节点而言,都表示序列中的单个元素信息…

今天我来学习线段树

首先它是树有着'树'的结构,线段树由于本身是专门用来处理区间问题的

它的作用可以处理区间的问题拥有更快的速度.

对于每一个子节点而言,都表示整个序列中的一段子区间;对于每个叶子节点而言,都表示序列中的单个元素信息;子节点不断向自己的父亲节点传递信息,而父节点存储的信息则是他的每一个子节点信息的整合(信息的整合可能是求和,也可能是最大值,也可能是最小值)。

就是一个分块的思想.

一个大的区间不断的被二分找到区间的长度为1,

如上图每一个区间就是一个节点. 

 

数组3 1 2 4 就如上图一般

1节点代表区间1到4

2为1到2 3表示3到4

由于线段树满足完全二叉树,

节点x的左子节点为2x

右子节点为2x+1

用数组非长好的就可以实现.

以下的代码我一求区间的和为样例,用数组来模拟树的节点

int lchid(int x){//找左兒子
return 2*x;}int rchid(int x){//找右兒子
return 2*x+1;}

这两函数就是直接找到你的二子的下标的. (其实也可以不写的,但是有的话调用就好了完全不用想).

这里选定的是求和的关系

tree数组的树的节点

void sum(int p){//向上维护(求和)
tree[p]=tree[lchid(p)]+tree[rchid(p)];
}

然后就是建树

p是当前节点的下标,l和r是p节点的区间标

void build(int p,int l,int r){
if(r==l){tree[p]=a[l];return ;
}
int mid=(l+r)/2;
build(lchid(p),l,mid);//向左边的区间递归
build(rchid(p),mid+1,r);//向右区间进行递归
sum(p);//对当前的节点进行维护(赋值);
}
//区间建树

到了区间长度为一的节点就赋值(给叶子节点赋值)

用到是是递归,一直递归下去要是出现赋值的数目超过了比如区间为3但是会有4个叶子节点

直接赋值为0即可

有时我们要修改某个区间的值

void updata(int ll,int rr,int l,int r,int p,int k){
//ll,rr是要修改的区间
//l,r是当前节点的区间p是当前节点的编号
//k是要修改的值(可能是加,也可能是减)if(ll<=l&&rr>=r){//修改的区间完全包含当前区间lazyr(l,r,p,k);return ;
}
donm(p,l,r);
//要是当前的区间没有匹配的话就要对下面的节点进行更新了
int mid=(r+l)/2;
if(ll<=mid) updata(ll,rr,l,mid,lchid(p),k);if(rr>mid) updata(ll,rr,mid+1,r,rchid(p),k);sum(p);//对当前的节点要更新的}
//区间修改
void lazyr(int l,int r,int p,int k){//改变区间的和,并打上lazy标记
lazy[p]+=k;
tree[p]+=k*(r-l+1);
}
void donm(int p,int l,int r){//k就是p节点的lazy值,向下传递lazy值int mid=(l+r)/2;lazyr(l,mid,lchid(p),lazy[p]);lazyr(mid+1,r,rchid(p),lazy[p]);lazy[p]=0;//把lazy向下传递后自己的lazy清空}

你会问为啥要这样写

1,线段树在对区间处理时是用当前的区间与要处理的区间的包含关系来处理的

2类情况

1操作的区间包含当前的区间,就直接返回当前节点的区间值

2只有左或者右区间的端点包含,那就递归下去知道包含为止

2.为何要用到lazy数组以及donm函数

注意重点来了!

如果我们要对区间的值进行修改,非要递归到区间长度为一的时候进行修改,那线段树比起简单的数组处理区间就完全没有优势了,复杂度还会略高一点

所以就有了,每个节点的lazy值

lazy值就是要改的区间与包含当前的区间

那就不用继续往下更新了,直接把此节点的区间的值改了并且给一个lazy值表示这个节点,的子节点还未更新,要更新的值就是p的lazy值

我们不更新下面的值那下面的值不是错了吗?

当然有方法的,下次当我们要递归到本节点的子节点是

要判断当前的节点的lazy值(>0就是存在)

那就更新两个子节点的值即可,也不用再往下了.

这样就不会一修改就直接到叶子节点了

要用到了再修改

思想就是延迟更新

区间求和

ll find(int ll,int rr,int l,int r,int p){if(ll<=l&&rr>=r){//修改的区间完全包含当前区间ans+=tree[p];return 0;}
donm(p,l,r);//要是当前的区间没有匹配的话就要对下面的节点进行更新了
int mid=(r+l)/2;
if(ll<=mid) find(ll,rr,l,mid,lchid(p));if(rr>mid) find(ll,rr,mid+1,r,rchid(p));return ans;
}

依旧是递归遍历

要是要用到子节点就以lazy判断要不要更新(我没判断,lazy=0,在函数中不会对数据有改变,但是判断了运行速度会快一点点)

ok讲了这摩多

来个板子吧!

 复制Markdown  展开

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 �k。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 �,�n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 �n 个用空格分隔的整数,其中第 �i 个数字表示数列第 �i 项的初始值。

接下来 �m 行每行包含 33 或 44 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [�,�][x,y] 内每个数加上 �k。
  2. 2 x y:输出区间 [�,�][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例

输入 #1复制

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

输出 #1复制

11
8
20

说明/提示

对于 30%30% 的数据:�≤8n≤8,�≤10m≤10。
对于 70%70% 的数据:�≤103n≤103,�≤104m≤104。
对于 100%100% 的数据:1≤�,�≤1051≤n,m≤105。

保证任意时刻数列中所有元素的绝对值之和 ≤1018≤1018。

【样例解释】

出自洛谷:p3372

#include<stdio.h>
#define maxsize 100000
typedef long long ll;//long long 麻烦好长的就用ll
ll tree[maxsize*4];//用數字模擬樹
int lazy[maxsize*4]={0};//lazy數組
int a[100050];
ll ans=0;int lchid(int x){//找左兒子
return 2*x;}int rchid(int x){//找右兒子
return 2*x+1;}void sum(int p){//向上维护(求和)
tree[p]=tree[lchid(p)]+tree[rchid(p)];
}void lazyr(int l,int r,int p,int k){//改变区间的和,并打上lazy标记
lazy[p]+=k;
tree[p]+=k*(r-l+1);
}void donm(int p,int l,int r){//k就是p节点的lazy值,向下传递lazy值int mid=(l+r)/2;lazyr(l,mid,lchid(p),lazy[p]);lazyr(mid+1,r,rchid(p),lazy[p]);lazy[p]=0;//把lazy向下传递后自己的lazy清空}
//lazy下传的函数void build(int p,int l,int r){
if(r==l){tree[p]=a[l];return ;
}
int mid=(l+r)/2;
build(lchid(p),l,mid);//向左边的区间递归
build(rchid(p),mid+1,r);//向右区间进行递归
sum(p);//对当前的节点进行维护(赋值);
}
//区间建树void updata(int ll,int rr,int l,int r,int p,int k){
//ll,rr是要修改的区间
//l,r是当前节点的区间p是当前节点的编号
//k是要修改的值(可能是加,也可能是减)if(ll<=l&&rr>=r){//修改的区间完全包含当前区间lazyr(l,r,p,k);return ;
}
donm(p,l,r);
//要是当前的区间没有匹配的话就要对下面的节点进行更新了
int mid=(r+l)/2;
if(ll<=mid) updata(ll,rr,l,mid,lchid(p),k);if(rr>mid) updata(ll,rr,mid+1,r,rchid(p),k);sum(p);//对当前的节点要更新的}
//区间修改ll find(int ll,int rr,int l,int r,int p){if(ll<=l&&rr>=r){//修改的区间完全包含当前区间ans+=tree[p];return 0;}
donm(p,l,r);//要是当前的区间没有匹配的话就要对下面的节点进行更新了
int mid=(r+l)/2;
if(ll<=mid) find(ll,rr,l,mid,lchid(p));if(rr>mid) find(ll,rr,mid+1,r,rchid(p));return ans;
}
//区间求和int main(){int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);build(1,1,n);//起始点为1,区间为1到n的建树
while(m--){int q,w,e,r;scanf("%d",&q);if(q==1){scanf("%d%d%d",&w,&e,&r);updata(w,e,1,n,1,r);}else{ans=0;scanf("%d%d",&w,&e);printf("%lld\n",find(w,e,1,n,1));}
}
return 0;
}

没得解释,就是板子题,算法的每一行都有我的理解和注释

该算法刚学不熟悉,看着大佬的题解来的

每一行都尽量的去理解

这就是我的忍道!

ok 撒花谢幕!!!!!

http://www.hotlads.com/news/2115.html

相关文章:

  • 网站开发的兼职网站semir
  • 做网站多少钱一张页面网络广告投放公司
  • 小说类网站怎么做怎么制作一个简单的网页
  • 有什么手机做网站的百度推广案例及效果
  • 展览展示设计必看网站百度精准搜索
  • wordpress个人下载网站模板下载淘宝客怎么做推广
  • 做视频网站需要什么职位工作哪里有学电脑培训班
  • 做网站用哪个电脑网络营销与直播电商
  • 网站开发有名的公司微信seo排名优化软件
  • 北京网站平台建设公司百度在线扫题入口
  • 没有网站可以做百度快照怎么做免费建站网站
  • 网站制作怎么办网络营销常用的工具和方法
  • 网站宣传专利被罚关键词查找
  • 网站管理系统 手机如何推广软件
  • 一米八效果图网站谷歌浏览器chrome官网
  • 怎样做免费网站建设好用的视频播放器app
  • 怎么让网站收录seo是什么职务
  • 做一个wordpress模板aso排名优化
  • 大兴区住房和城乡建设部网站网络营销软文范例300字
  • 做两个阿里网站吗软件编程培训学校排名
  • 大家做公司网站 都是在哪里做的福州seo推广外包
  • dreamweaver做网页教程hyein seo
  • 河南省教育类网站前置审批营销方案模板
  • 重庆旅游网页制作优化seo厂家
  • 做基础网站主机要百度搜不干净的东西
  • 重庆慕尚网站建设今日小说排行榜风云榜
  • 做淘宝客需要那先网站百度竞价开户
  • 用vs2010做网站导航软文怎么写
  • 大良网站建设dwxw真正免费的网站建站平台运营
  • 网站设计技术公司搜索引擎优化期末考试答案