博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树状数组和线段树的总结
阅读量:5039 次
发布时间:2019-06-12

本文共 2431 字,大约阅读时间需要 8 分钟。

先说树状数组吧  主要有lowbit,update,getsum

int lowbit(int x){    return x&(-x);}
int update(int x,int date){    while(x<=y)    {        c[x]+=date;        x+=lowbit(x);    }}
int getsum(int x){    int ans=0;    while(x>0)    {        ans+=c[x];        x-=lowbit(x);    }    return ans;}

lowbit的作用就是找到该节点的父节点或子节点   图 (https://www.cnblogs.com/George1994/p/7710886.html)

注意了  a数组存的是原来的数  c数组的意义代表着c[i] 就是前i项的和

 

线段树的话

差不多两个数组搞定一个tree【n】和一个add【n】

先是建立树

线段树是从1这个节点开始的

void build(int l,int r,int k)//l,r为建树的范围 {    if(l==r)    {        cin>>tree[k];        return ;    }    int m=(l+r)>>1;    build(l,m,k<<1);//递归建立数     build(m+1,r,k<<1|1);    tree[k]=tree[k<<1]+tree[k<<1|1];//求和 }

 

自我觉得这个是比较灵活的,对这个改动一下就成为不同的功能,比如最大值

void build(int l,int r,int k){    if(l==r)    {        cin>>tree[k];        return ;    }    int m=(l+r)>>1;    build(l,m,k<<1);    build(m+1,r,k<<1|1);    //tree[k]=tree[k<<1]+tree[k<<1|1];    tree[k]=max(tree[k<<1],tree[k<<1|1]); }

这样就变成了父节点 为子节点的最大值

 

然后是点更新

void update(int ee,int c,int l,int r,int k){    if(l==r)    {        tree[k]+=c;        //tree[k]=c;  这样就是更改这个数,而不是加         return ;    }    int m=(l+r)>>1;    if(ee<=m) update(ee,c,l,m,k<<1);//ee为需要更新的叶子节点,通过递归找     else update(ee,c,m+1,r,k<<1|1);    tree[k]=tree[k<<1]+tree[k<<1|1];}

 

然后是区间更新  ,这里需要懒标记,这个确实比较难理解

void update(int x,int y,int c,int l,int r,int k)//x,y为需要更新区间,l,r为k这一节点的管理范围 {    if(x<=l&&y>=r)    {        tree[k]=c*(r-l+1);//这一点为c乘以这一点管理的数量        add[k]=c;//把这一点标记一下,为懒标记        return;//注意是结束了     }    int m=(l+r)>>1;    pushdown(k,m-l+1,r-m);//下推标记    if(x<=m) update(x,y,c,l,m,k<<1);    if(y>m) update(x,y,c,m+1,r,k<<1|1);//注意 这里不是else 而是都要更新并查找     tree[k]=tree[k<<1]+tree[k<<1|1]; }
void pushdown(int k,int ln,int rn)//ln,rn为左子树,右子树的数字数量。 {    if(add[k])    {        add[k<<1]+=add[k];        add[k<<1|1]+=add[k];//传递这个标记                sum[k<<1]+=add[k]*ln;        sum[k<<1|1]+=add[k]*rn;        add[k]=0;    }}

上面是要求和的下推标记,但如果说是这道题

为这个区间都改变成一样的数,而不是相加一样的数

void pushdown(int k,int ln,int rn){    if(add[k]){        add[k<<1]=add[k];        add[k<<1|1]=add[k];         sum[k<<1]=add[k]*ln;        sum[k<<1|1]=add[k]*rn;        add[k]=0;    }}

 

最后是区间求和

int query(int x,int y,int l,int r,int k){    if(x<=l&&r<=y)    {        return tree[k];    }    int m=(l+r)>>1;    pushdown(k,m+1-l,r-m);        int ans=0;    if(x<=m) ans+=query(x,y,l,m,k<<1);    if(y>m) ans+=query(x,y,m+1,r,k<<1|1);    return ans;}

 

转载于:https://www.cnblogs.com/wpbing/p/9370304.html

你可能感兴趣的文章
次序+“选择不重复的记录”(3)——最大记录
查看>>
Codeforces 450 C. Jzzhu and Chocolate
查看>>
[Unity3D]Unity3D游戏开发MatchTarget的作用攀登效果实现
查看>>
ACdream 1115 Salmon And Cat (找规律&amp;&amp;打表)
查看>>
JSON、JSONP、Ajax的区别
查看>>
AngularJS学习篇(一)
查看>>
【转载】 IP实时传输协议RTP/RTCP详解
查看>>
关于Xshell无法连接centos6.4的问题
查看>>
Linux系统的数据写入机制--延迟写入
查看>>
css3动画——基本准则
查看>>
SQLite详解,案例,手册
查看>>
创建自己的内容提供器
查看>>
SSRS 数据源访问Cube 无法创建订阅的解决方法
查看>>
Spring之SpringMVC
查看>>
[转载]限制排列与棋盘多项式{理论}
查看>>
cookie、session 整理
查看>>
js 设计模式——观察者模式
查看>>
[nowcoder]再编号
查看>>
redis学习小结
查看>>
pku 3041 Asteroids 二分图匹配——匈牙利算法求最小点覆盖
查看>>