线段树--区间合并--HDU 1540

题意:

题意:D: 破坏村庄,R:修复最后一个破损的村庄,Q:查找X在内的连续区间值有多少

思路:

建立线段树,维护左右区间值。注意维护变量为: 从左编开始最大连续值,从右边开始最大值,最大连续值 

为了维护最后一个被破坏的。需要时刻记录,并且不能只单纯记录一个,而是需要记录顺序。满足先入后出的栈操作,传参即可 

#include <iostream>
#define lson i<<1,left,mid
#define rson i<<1|1,mid+1,right
#include <stdio.h>
#include <cstring>
using namespace std;
#define maxn  50010

int s[maxn],top;
int n,m;
struct TreeNode
{
    int left;
    int right;
    int ls,rs,ms;
}a[maxn*3];
void Build(int i,int left,int right)
{
    a[i].ls=a[i].rs=a[i].ms=right-left+1;
    a[i].left=left;
    a[i].right=right;
    if(left==right)
        return ;
    int mid=(left+right)>>1;
    Build(lson);
    Build(rson);
}
void insert(int i,int t,int x)
{
    if(a[i].left==a[i].right)
    {
        if(x==1)
            a[i].ls=a[i].rs=a[i].ms=1;
        else
            a[i].ls=a[i].rs=a[i].ms=0;
        return ;
    }
    int mid=(a[i].left+a[i].right)>>1;
    if(t<=mid)
        insert(i<<1,t,x);
    else
        insert(i<<1|1,t,x);

    a[i].ls=a[i<<1].ls;
    a[i].rs=a[i<<1|1].rs;
    a[i].ms=max(max(a[i<<1].ms,a[i<<1|1].ms),a[i<<1].rs+a[i<<1|1].ls);
    if(a[i<<1].ls==a[i<<1].right-a[i<<1].left+1)
        a[i].ls+=a[i<<1|1].ls;
    if(a[i<<1|1].rs==a[i<<1|1].right-a[i<<1|1].left+1)
        a[i].rs+=a[i<<1].rs;
}
int query(int i,int t)
{
    if(a[i].left==a[i].right||a[i].ms==a[i].right-a[i].left+1)
        return a[i].ms;
    int mid=(a[i].left+a[i].right)>>1;
    if(t<=mid)
    {
        if(t>=a[i<<1].right-a[i<<1].rs+1)
            return query(i<<1,t)+query(i<<1|1,mid+1);
        else
            return query(i<<1,t);

    }
    else
    {
        if(t<=a[i<<1|1].left+a[i<<1|1].ls-1)
            return query(i<<1|1,t)+query(i<<1,mid);
        else
            return query(i<<1|1,t);
    }
}int main()
{
    int i,j,x;
    char ch[2];
    while(~scanf("%d%d",&n,&m))
    {
        top = 0;
        Build(1,1,n);
        while(m--)
        {
            scanf("%s",ch);
            if(ch[0] == 'D')
            {
                scanf("%d",&x);
                s[top++] = x;
                insert(1,x,0);
            }
            else if(ch[0] == 'Q')
            {
                scanf("%d",&x);
                printf("%d\n",query(1,x));
            }
            else
            {
                if(x>0)
                {
                    x = s[--top];
                    insert(1,x,1);
                }
            }
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值