线段树(优雅暴力)从入门到入坟

当OI考试想不到正解,抓耳挠腮,准备爆零或者打表的时候

你或许可以考虑用线段树来打个暴力卡过或者拿60分
当然,如果你随便打个暴力,能卡个20分就算是信仰极高 幸运的玩家了

所以废物来讲一下线段树的入门,真就是入门,没学过c++也会的那种

先从思路入手,假设我们要维护一个数组(序列),假设让你在某个区间同时加上一个数或者求和区间乘一个数的时候,大多数人选择暴力求解

那你AC 寄了,单次的查询需要O(N)的复杂度,但是线段树只有O(logN),嘎嘎快

正文

---------------------------------------

重点来了,线段树的核心思路就是把整个序列从中间拆开,一直拆,一直拆,一直拆,一直拆,拆到不能拆为止,也就是说l==r时停止

大概是这样

在这里插入图片描述

你已经学会了最基本的提高算法的思路,试着挑战最菜的lxl吧

然后是代码的实现,从定义树开始,建树我们考虑用结构体,我们需要记录这个区间的区间和,这个区间的左边界和右边界

以及一个add(懒标记,顾名思义,很懒但是节省时间,说不定靠信仰卡过70分)笑死我了傻逼别想了

定义树代码如下

struct T{
   
    int l,r;//左右边界 
	ll sum,add;//区间和以及懒标记 
}tree[4*N];

好了,你已经会定义线段树了,去挑战一个叫_rqy的新手吧

将这个树建立起来也很简单,如果说tree[i].l==tree[i].r,那么就是说我到了一个叶子节点,可以赋值

如果不是叶子节点,则我们考虑找他的左右儿子,定义一个mid=(tree[i].l+tree[i].r)/2,也就是他的左儿子的右边界,mid+1是右儿子的左边界

最后我们只需要让tree[i].sum=tree[i*2].sum+tree[i *2+1].sum就好了(当前的区间值是左右儿子的值的和)

建树代码如下

void build(int i,int l,int r){
   
    if(tree[i].l==tree[i].r){
   
        tree[i].sum=in_put[l];//in)_put是输入的数组 
        return ;
    }
    int mid=(tree[i].l+tree[i].r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}

前面讲到了一个叫懒标记的东西,非常之人性,非常之懒惰 就是说,如果我要访问你的儿子们,那我就把懒标记下方(将之前需要改动的数字加上)如果没有访问到,我就把他们塞到一个add里,需要的时候调用,不需要就烂肚子里

当然,加完以后要把add清零

懒标记代码如下

void add(int i){
   
    if(tree[i].add){
   
        tree[i*2].sum+=tree[i].add*(tree[i*2].r-tree[i*2].l+1);//改变左sum 
        tree[i*2
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值