【线段树专题】poj1823

本文介绍了一种使用区间树解决最大空子列问题的算法实现,通过维护左右最长空串长度及覆盖状态,实现了对区间进行更新并查询最长空子列的功能。

最大空子列


想到用lsum表示从左开始的最长空串,rsum表示从右开始的最长空串。


还要用biao标记一下


-1表示完全不覆盖

0表示有的覆盖有的不覆盖

1表示完全覆盖

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

int tot=0,n,q;

struct rec
{
    int lch,rch,lsum,rsum,maxf,l,r,sum,biao;
}tree[300100];

void clear()
{
    memset(tree,0,sizeof(tree));
    tot=0;
}
void maketree(int l,int r)
{
    int now=++tot;
    tree[now].l=l,tree[now].r=r,tree[now].biao=-1;
    if (l==r) 
    {
        tree[now].lsum=1;
        tree[now].rsum=1;
        tree[now].maxf=1;
        return;
    }
    int mid=(l+r)>>1;
    tree[now].lch=tot+1;maketree(l,mid);
    tree[now].rch=tot+1;maketree(mid+1,r);
    tree[now].lsum=tree[tree[now].lch].lsum+tree[tree[now].rch].lsum;
    tree[now].rsum=tree[tree[now].lch].lsum+tree[tree[now].rch].lsum;
    tree[now].maxf=tree[tree[now].lch].lsum+tree[tree[now].rch].lsum;
}

void updata_tree(int x)
{
    int lc=tree[x].lch;
    int rc=tree[x].rch;
    tree[x].maxf=max(tree[lc].maxf,tree[rc].maxf);
    int tmp=tree[lc].rsum+tree[rc].lsum;
    tree[x].maxf=max(tree[x].maxf,tmp);
    if (tree[lc].biao==-1)
        tree[x].lsum=tree[lc].lsum+tree[rc].lsum;
    else
        tree[x].lsum=tree[lc].lsum;
    if (tree[rc].biao==-1)
        tree[x].rsum=tree[rc].rsum+tree[lc].rsum;
    else 
        tree[x].rsum=tree[rc].rsum;
    if (tree[lc].biao==tree[rc].biao)
        tree[x].biao=tree[lc].biao;
}

void change(int x,int l,int r,int w)
{
    if (tree[x].l>=l&&tree[x].r<=r)
    {
        if (w==-1) 
        {
            int len=tree[x].r-tree[x].l+1;
            tree[x].lsum=tree[x].rsum=tree[x].maxf=len;
        }
        if (w==1)
        {
            tree[x].lsum=tree[x].rsum=tree[x].maxf=0;
        }
        tree[x].biao=w;
        return ;
    }
    if (tree[x].biao==-1)
    {
        tree[x].biao=0;
        tree[tree[x].lch].biao=-1;
        tree[tree[x].rch].biao=-1;
        tree[tree[x].lch].lsum=tree[tree[x].lch].rsum=tree[tree[x].lch].maxf=tree[tree[x].lch].r-tree[tree[x].lch].l+1;
        tree[tree[x].rch].lsum=tree[tree[x].rch].rsum=tree[tree[x].rch].maxf=tree[tree[x].rch].r-tree[tree[x].rch].l+1;
    }
    if (tree[x].biao==1)
    {
        tree[x].biao=0;
        tree[tree[x].lch].biao=1;
        tree[tree[x].rch].biao=1;
        tree[tree[x].lch].lsum=tree[tree[x].lch].rsum=tree[tree[x].lch].maxf=0;
        tree[tree[x].rch].lsum=tree[tree[x].rch].rsum=tree[tree[x].rch].maxf=0;
    }
    int mid=(tree[x].l+tree[x].r)>>1;
    if (l<=mid) change(tree[x].lch,l,r,w);
    if (r>mid) change(tree[x].rch,l,r,w);
    updata_tree(x);
}
int main()
{
    freopen("poj1823.in","r",stdin);
    freopen("poj1823.out","w",stdout);
    int ch=0,l,r;
    clear();
    scanf("%d%d",&n,&q);
    maketree(1,n);
    for (int i=1;i<=q;i++)
    {
        scanf("%d",&ch);
        if (ch==3) printf("%d\n",tree[1].maxf);
        if (ch==1)
        {
            scanf("%d%d",&l,&r);
            change(1,l,l+r-1,1);
        }
        if (ch==2)
        {
            scanf("%d%d",&l,&r);
            change(1,l,l+r-1,-1);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值