题解小白逛公园(zkw线段树造树修改+回溯查询写法)

本文介绍了一种基于线段树的数据结构实现方法,用于高效地进行区间最大值的查询和更新操作。通过维护每个节点的多种属性,如最大值、左侧最大值、右侧最大值及区间和等,该方法能够快速响应各种查询请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://vijos.org/p/1083
这题让维护子区间最大值,查询子区间最大值
于是在父亲节点的子区间最大值可能
1. 完全在左儿子中
2. 完全在右儿子中
3. 左右儿子各一半
于是就有

segtree[i].smax=max(max(segtree[i<<1].smax,segtree[(i<<1)^1].smax),segtree[(i<<1)^1].lmax+segtree[i<<1].rmax);

所以就要维护:1.子区间最大值 2.区间从最左开始最大值 3. 区间从最右开始最大值。
于是就有

segtree[i].lmax=max(segtree[i<<1].lmax,segtree[i<<1].sum+segtree[(i<<1)^1].lmax);
        segtree[i].rmax=max(segtree[(i<<1)^1].rmax,segtree[(i<<1)^1].sum+segtree[i<<1].rmax);

segtree[i].smax=max(max(segtree[i<<1].smax,segtree[(i<<1)^1].smax),segtree[(i<<1)^1].lmax+segtree[i<<1].rmax);

所以还要维护:区间和
于是就有

segtree[i].sum=segtree[i<<1].sum+segtree[(i<<1)^1].sum;

最后注意一下query()的写法
最后上代码

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

int m=1,n,qu;
struct o
{
    int lmax;
    int rmax;
    int smax;
    int sum;

}segtree[2000000];

o query(int pos,int l,int r,int f,int t)
{
    int mid=(l+r)>>1;
    if(l>=f&&r<=t)
        return segtree[pos];
    else if(t<=mid)
        return query(pos<<1,l,mid,f,t);
    else if(f>mid)
        return query((pos<<1)+1,mid+1,r,f,t);
    else 
    {
        o w1=query(pos<<1,l,mid,f,t);
        o w2=query((pos<<1)+1,mid+1,r,f,t);
        int relmax=max(w1.lmax,w1.sum+w2.lmax);
        int rermax=max(w2.rmax,w1.rmax+w2.sum);
        int resum=w1.sum+w2.sum;
        int resmax=max(max(w1.smax,w2.smax),w1.rmax+w2.lmax);
        return (o){relmax,rermax,resmax,resum};
    }
}

int main()
{
    scanf("%d%d",&n,&qu);
    while(m<=n)m<<=1;
    for(int i=m+1;i<=m+n;i++)
    {
        scanf("%d",&segtree[i].lmax);
        segtree[i].rmax=segtree[i].lmax;
        segtree[i].smax=segtree[i].lmax;
        segtree[i].sum=segtree[i].lmax;
    }
    for(int i=m-1;i>=1;i--)
    {
        segtree[i].lmax=max(segtree[i<<1].lmax,segtree[i<<1].sum+segtree[(i<<1)^1].lmax);
        segtree[i].rmax=max(segtree[(i<<1)^1].rmax,segtree[(i<<1)^1].sum+segtree[i<<1].rmax);
        segtree[i].sum=segtree[i<<1].sum+segtree[(i<<1)^1].sum;
        segtree[i].smax=max(max(segtree[i<<1].smax,segtree[(i<<1)^1].smax),segtree[(i<<1)^1].lmax+segtree[i<<1].rmax);
    }
    int temp=0;
    for(int i=1;i<=qu;i++)
    {
        int t,x,y;
        scanf("%d%d%d",&t,&x,&y);
        if(t==2)
        {
            segtree[x+m].sum=y;
            segtree[x+m].lmax=y;
            segtree[x+m].rmax=y;
            segtree[x+m].smax=y;
            for(int i=(x+m)>>1;i;i>>=1)
            {
                segtree[i].lmax=max(segtree[i<<1].lmax,segtree[i<<1].sum+segtree[(i<<1)^1].lmax);
                segtree[i].rmax=max(segtree[(i<<1)^1].rmax,segtree[(i<<1)^1].sum+segtree[i<<1].rmax);
                segtree[i].sum=segtree[i<<1].sum+segtree[(i<<1)^1].sum;
                segtree[i].smax=max(max(segtree[i<<1].smax,segtree[(i<<1)^1].smax),segtree[(i<<1)^1].lmax+segtree[i<<1].rmax);
            }
        }else
        {
            if(temp==1)
                printf("\n");
            else temp=1;
            if(x>y)swap(x,y);
            printf("%d",query(1,0,m-1,x,y).smax);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值