HDU1540(线段树- 连续区间问题,区间合并与破坏)

题目链接

#include<bits/stdc++.h>

using namespace std;
const int maxn = 5e4+50;

struct node
{
    int l, r;
    int ls, rs, ms;// 该区间 最左端最大连续区间, 最右端最大连续区间,该区间内最大区间
} Segtr[maxn*4];

stack<int>s;

void build(int rt,int L, int R)
{
    Segtr[rt].l = L;
    Segtr[rt].r = R;
    Segtr[rt].ls = Segtr[rt].rs = Segtr[rt].ms = (R-L+1);

    if(L == R)
    {
        return;
    }
    int mid = (L+R)/2;

    build(rt*2+1, L, mid);
    build(rt*2+2, mid+1, R);
}

void update(int rt, int x, int op)
{
    if(Segtr[rt].l == Segtr[rt].r)
    {
        if(op == 1)//修复
            Segtr[rt].ls = Segtr[rt].rs = Segtr[rt].ms = 1;
        else
            Segtr[rt].ls = Segtr[rt].rs = Segtr[rt].ms = 0;
        return ;
    }
    int mid = (Segtr[rt].l +Segtr[rt].r)/2;

    if(x <= mid)
    {
        update(rt*2+1, x, op);
    }
    else
    {
        update(rt*2+2, x, op);
    }
    Segtr[rt].ls = Segtr[rt*2+1].ls;
    Segtr[rt].rs = Segtr[rt*2+2].rs;
    Segtr[rt].ms = max(max(Segtr[2*rt+1].ms, Segtr[rt*2+2].ms), Segtr[rt*2+1].rs+Segtr[rt*2+2].ls);

    if(Segtr[rt*2+1].ls == Segtr[rt*2+1].r- Segtr[rt*2+1].l+1)
    {
        Segtr[rt].ls +=Segtr[rt*2+2].ls;
    }

    if(Segtr[rt*2+2].rs  == Segtr[rt*2+2].r - Segtr[rt*2+2].l +1)
    {
        Segtr[rt].rs += Segtr[rt*2+1].rs;
    }


}
int query(int rt, int x)
{
    int l = Segtr[rt].l;
    int r = Segtr[rt].r;
    //如果 查询的 节点所在的父区间 为 0 为 满 或者到达叶子节点 直接返回, 不在往下询问
    if(Segtr[rt].l == Segtr[rt].r ||Segtr[rt].ms == 0|| Segtr[rt].r - Segtr[rt].l + 1== Segtr[rt].ms)
        return Segtr[rt].ms;

    int mid = (l + r)/2;

    if(x <= mid)
    {
        if(x >= Segtr[rt*2+1].r - Segtr[rt*2+1].rs+1) // 判断要查询的是否 在 左节点右端最大连续区间内
        {
            return query(rt*2+1, x)+query(rt*2+2, mid+1);
        }
        else
        {
            return query(rt*2+1, x);
        }
    }
    else
    {
        if( x<=Segtr[rt*2+2].l+Segtr[rt*2+2].ls-1 )// 判断要查询寻的节点是否在右节点左端最大连续区间内
        {
            return query(rt*2+1, mid)+ query(rt*2+2, x);
        }
        else return query(rt*2+2, x);
    }

}

void init()
{
    while(!s.empty())s.pop();
}

int main()
{
    ios_base::sync_with_stdio(false);
    int n, m;
    char op;
    int x;
    while(cin>>n>>m)
    {

        init();
        build(0, 1, n);

        for(int i = 0;i < m;i++)
        {
            cin>>op;
            if(op!= 'R')cin>>x;
            if(op == 'D')
            {
                update(0 , x, 0);
                s.push(x);
            }
            else if(op == 'Q')
            {
                int ans = query(0, x);
                cout << ans<<endl;
            }
            else
            {
                int tp = s.top();
                s.pop();
                update(0, tp, 1);
            }
        }

    }
    return 0;
}

一个区间内的最大连续区间:
要么是左儿子的最大连续区间 , 要么是右儿子的最大连续区间 。

要么是做儿子右端区间+ 右儿子左端区间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值