线段树总结与模板

线段树也是一种高级数据结垢,经典的log型。

树状数组能做的事它都能做(单点修改区间求和与区间修改单点查询),它能做的事树状数组不一定能做(区间修改区间查询或查询最大值)。

这里有俩例题,代码风格也不太一样,大家将就一点。

这道题需要单点修改区间查询最大值,用树状数组事维护不了的,只好上一个线段树。

build一个结构体存储的树,每个节点控制一段原数组的区间。刚开始什么都没有,我们把它的左右节点弄好。

build(1,1,n);
void build(int now,int zuo,int you)
{
    o[now].zuo=zuo;o[now].you=you;
    if(zuo==you)return ;
    int mid=(zuo+you)/2;
    build(now*2,zuo,mid);
    build(now*2+1,mid+1,you);
}

对于每个修改操作,就直接冲到最里面把对应的叶子节点改掉,然后更新自己的max。

cin>>tx>>tv;
change(1);
void change(int now)
{
    if(o[now].zuo==o[now].you)
    {
        o[now].maxx=tv;
        return ;
    }
    int mid=(o[now].zuo+o[now].you)/2;
    if(tx<=mid)change(now*2);
    else       change(now*2+1);
    o[now].maxx=max(o[now*2].maxx,o[now*2+1].maxx);
    return ;
}

对于每个询问操作,如果当前节点管的区间被询问的区间包含,那么可以直接输出当前的max。否则我们要去看左右节点关于这个区间怎么说。

cin>>tz>>ty;//t左,t右
cout<<ask(1)<<endl;
int ask(int now)
{
    if(tz<=o[now].zuo&&o[now].you<=ty)
        return o[now].maxx;
    int mid=(o[now].zuo+o[now].you)/2,ans=0;
    if(tz<=mid)ans=ask(now*2);
    if(ty>mid) ans=max(ans,ask(now*2+1));
    return ans;
}

本题是一道区间修改区间查询。这个就要难很多了,我们需要一个懒标记add[],每次修改的时候有时可以只改懒标记就不更改子节点,每次查询的时候再带着懒标记;

具体实现过程(以区间最大值举例):每次修改或查询完后的maxx等上面的add传下来后一定是正确的.这句话非常重要.因为有这个性质,每次修改时如果修改的区间完全覆盖当前节点负责的区间可以直接把maxx+=,add+=,每次查询时我们如果完全覆盖可以直接returnmaxx.为了维护这个性质,如果没有完全覆盖就需要先pushdown,把儿子的maxx+=,add+=.确保了儿子的性质后自己的add就可以归零,然后去查询两个儿子.

做这道题的时候突然发现可以不用结构体,函数自带l,r也行,只不过三个参数看起来很难受(玩的花),那么这样子就用不到build建树了。


对于每个change,输入tr,tl作为全局变量,然后调用函数change(1,1,n),三个参数是now,l,r。now表示当前处于下标为now的节点上,管的是区间l到r的数。那么如果这个节点管的区间在tr,tl之间那么令max[now]++,add[now]++,ruturn即可。这时子节点们都还没有更新(重要!)
如果不是全部覆盖,就需要二分当前区间把需要改的改掉。
先把自己的add传到下面,pushdown一次,确保子节点的正确性。

改完子节点后回来更新自己的max[now]=max(max[lc],max[rc]);在这些操作中可以看到如果时叶子节点即l[now]==r[now]的时一定直接return的,不会参与pushdown。而且每次带进去的参数l,r已经告诉我now管控的范围了,就不需要写结构体。

cin>>tl>>tr;
change(1,1,n);

void pushdown(int now)
{
    if(add[now])
    {
        add[now<<1]+=add[now];
        add[(now<<1)+1]+=add[now];
        maxx[now<<1]+=add[now];
        maxx[(now<<1)+1]+=add[now];
        add[now]=0;
    }
}


void change(int now,int l,int r)
{
    if(tl<=l&&r<=tr)
    {
        maxx[now]++;
        add[now]++;
        return;
    }
    int mid=(l+r)/2;
    int lc=now<<1;
    int rc=(now<<1)+1;
    pushdown(now);
    if(tl<=mid)
        change(lc,l,mid);
    if(tr>mid)
        change(rc,mid+1,r);
    maxx[now]=max(maxx[lc],maxx[rc]);
}


对于每次询问
依旧全局变量tr,tl,cout<<ask(1,1,n)。
如果tl<=l&&r<=tr可以直接return max[now];因为既然来了,就确保max已经被更新过了
否则pushdown,询问下面的子节点并且return ;

cin>>tr>>tl;
cout<<ask(1,1,n);
int ask(int now,int l,int r)
{
    if(tl<=l&&r<=tr)
        return maxx[now];
    int mid=(l+r)/2;
    int lc=now<<1;
    int rc=(now<<1)+1;
    pushdown(now);
    int ans=0;
    if(tl<=mid)
        ans=ask(lc,l,mid);
    if(tr>mid)
        ans=max(ans,ask(rc,mid+1,r));
    return ans;
}

 

转载于:https://www.cnblogs.com/qywyt/p/9618984.html

内容概要:本文详细介绍了施耐德M580系列PLC的存储结构、系统硬件架构、上电写入程序及CPU冗余特性。在存储结构方面,涵盖拓扑寻址、Device DDT远程寻址以及寄存器寻址三种方式,详细解释了不同类型的寻址方法及其应用场景。系统硬件架构部分,阐述了最小系统的构建要素,包括CPU、机架和模块的选择配置,并介绍了常见的系统拓扑结构,如简单的机架间拓扑和远程子站以太网菊花链等。上电写入程序环节,说明了通过USB和以太网两种接口进行程序下载的具体步骤,特别是针对初次下载时IP地址的设置方法。最后,CPU冗余部分重点描述了热备功能的实现机制,包括IP通讯地址配置和热备拓扑结构。 适合人群:从事工业自动化领域工作的技术人员,特别是对PLC编程及系统集成有一定了解的工程师。 使用场景及目标:①帮助工程师理解施耐德M580系列PLC的寻址机制,以便更好地进行模块配置和编程;②指导工程师完成最小系统的搭建,优化系统拓扑结构的设计;③提供详细的上电写入程序指南,确保程序下载顺利进行;④解释CPU冗余的实现方式,提高系统的稳定性和可靠性。 其他说明:文中还涉及一些特殊模块的功能介绍,如定时器事件和Modbus串口通讯模块,这些内容有助于用户深入了解M580系列PLC的高级应用。此外,附录部分提供了远程子站和热备冗余系统的实物图片,便于用户直观理解相关概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值