[题解](线段树最大连续子段和)POJ_3667_Hotel

本文探讨了一种高效的数据结构——线段树,用于处理区间查询和更新问题。具体介绍了如何通过线段树维护最大连续子段和,实现区间元素的批量修改和查询最左侧满足条件的区间。通过实例代码,展示了线段树节点结构的设计,包括左、右子树的最大子段和,当前段最大子段长度,以及懒惰标记的使用。

题意:1.求一个最靠左的长x的区间全部为0,并修改为1,输出这个区间的左端点

2.修改一个区间为0

实际上是维护最大连续子段和,原来也写过

大概需要维护一个左/右最大子段和,当前这段最大子段长,再维护一个lazytag

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r>>1)
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int maxn=50009;
struct node{
    int l,r,mx,tg;//0全空,1全满,-1没有
}t[maxn<<2];
//inline void upd(int x,int l,int r){
//    t[x].l=t[ls].l;
//    t[x].r=t[rs].r;
////    if(t[ls].l==mid-l+1)t[x].l+=t[rs].l;
////    if(t[rs].r==r-mid)t[x].r+=t[ls].r;
//    if(t[ls].l==(r-l+1-(r-l+1)/2))t[x].l+=t[rs].l;
//    if(t[rs].r==(r-l+1)/2)t[x].r+=t[ls].r;
//    t[x].mx=max(max(t[ls].mx,t[rs].mx),t[ls].r+t[rs].l);
//}
//inline void pushdown(int x,int l,int r){
//    if(t[x].tg!=-1){
//        t[ls].tg=t[rs].tg=t[x].tg;
//        t[ls].l=t[ls].r=t[ls].mx=(r-l+1-(r-l+1)/2)*t[x].tg;
//        t[rs].l=t[rs].r=t[rs].mx=(r-l+1)/2*t[x].tg;
////        if(t[x].tg==0){
////            t[ls].l=t[ls].r=t[ls].mx=mid-l+1;
////            t[rs].l=t[rs].r=t[rs].mx=r-mid;    
////        }
////        else{
////            t[ls].l=t[ls].r=t[ls].mx=0;
////            t[rs].l=t[rs].r=t[rs].mx=0;
////        }
//        t[x].tg=-1;
//    }
//}
inline void pushdown(int x,int len){
    if(t[x].tg!=-1){
        t[ls].tg=t[rs].tg=t[x].tg;
        t[ls].mx=t[ls].l=t[ls].r=t[x].tg*(len-(len>>1));
        t[rs].mx=t[rs].l=t[rs].r=t[x].tg*(len>>1);
        t[x].tg=-1;
    }
}
inline void upd(int x,int len){
    t[x].l=t[ls].l;
    t[x].r=t[rs].r;
    if(t[x].l==len-(len>>1))t[x].l+=t[rs].l;
    if(t[x].r==(len>>1))t[x].r+=t[ls].r;
    t[x].mx=max(max(t[ls].mx,t[rs].mx),t[ls].r+t[rs].l);
}
void build(int x,int l,int r){
    t[x].l=t[x].r=t[x].mx=r-l+1;t[x].tg=-1;
    if(l==r)return;
    build(ls,l,mid);build(rs,mid+1,r);
}
void change(int x,int l,int r,int L,int R,int k){
    if(L<=l && r<=R){
        t[x].l=t[x].r=t[x].mx= k==0?0:r-l+1;
        t[x].tg=k;
        return;
    }
//    pushdown(x,l,r);
    pushdown(x,r-l+1);
    if(L<=mid)change(ls,l,mid,L,R,k);
    if(R>mid)change(rs,mid+1,r,L,R,k);
//    upd(x,l,r);
    upd(x,r-l+1);
}
int query(int x,int l,int r,int k){
    if(l==r)return 1;
//    pushdown(x,l,r);
    pushdown(x,r-l+1);
    if(t[ls].mx>=k)return query(ls,l,mid,k);
    else if(t[ls].r+t[rs].l>=k)return mid-t[ls].r+1;
    else return query(rs,mid+1,r,k);
}
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1,op,x,y;i<=m;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&x);
            if(t[1].mx<x)printf("0\n");
            else{
                int pos=query(1,1,n,x);
                printf("%d\n",pos);
                change(1,1,n,pos,pos+x-1,0);
            }
        }
        else{
            scanf("%d%d",&x,&y);
            change(1,1,n,x,x+y-1,1);
        }
    }
}

 

转载于:https://www.cnblogs.com/superminivan/p/11025449.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值