HDU1540Tunnel Warfare(线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540


题目大意:

一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。


分析:

线段树结点 设置一个  ll 记录区间左端点开始的最大连续个数,  rl 记录区间右端点开始的最大的连续个数, ml表示该区间最大的连续点的个数。 主要是更新和查询两个操作。

收获:
掌握区间合并的方式。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 50005;
struct Node
{
    int l, r;
    int ll, rl, ml;
}segTree[maxn<<2];
void Build(int rt, int l, int r)
{
    segTree[rt].l = l;
    segTree[rt].r = r;
    segTree[rt].ll = segTree[rt].rl = segTree[rt].ml = r - l + 1;
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    Build(rt<<1, l, mid);
    Build((rt<<1)|1, mid+1, r);
}
void update(int rt, int t, int val)
{
    if(segTree[rt].l == segTree[rt].r)
    {
        if(val == 1)
            segTree[rt].ll = segTree[rt].rl = segTree[rt].ml = 1;
        else
            segTree[rt].ll = segTree[rt].rl = segTree[rt].ml = 0;
        return ;
    }
    int mid = (segTree[rt].l + segTree[rt].r) >> 1;
    if(t <= mid)
        update(rt<<1, t, val);
    else
        update((rt<<1)|1, t, val);
    segTree[rt].ll = segTree[rt<<1].ll;
    segTree[rt].rl = segTree[(rt<<1)|1].rl;
    segTree[rt].ml = max(segTree[rt<<1].ml, segTree[(rt<<1)|1].ml);
    segTree[rt].ml = max(segTree[rt].ml, segTree[rt<<1].rl + segTree[(rt<<1)|1].ll);

    if(segTree[rt<<1].ll == segTree[rt<<1].r - segTree[rt<<1].l + 1)
        segTree[rt].ll += segTree[(rt<<1)|1].ll;
    if(segTree[(rt<<1)|1].rl == segTree[(rt<<1)|1].r - segTree[(rt<<1)|1].l + 1)
        segTree[rt].rl += segTree[rt<<1].rl;
}
int query(int rt, int t)
{
    if(segTree[rt].l == segTree[rt].r || segTree[rt].ml == 0 || segTree[rt].ml == segTree[rt].r - segTree[rt].l + 1)
    {
        return segTree[rt].ml;
    }
    int mid = (segTree[rt].l + segTree[rt].r) >> 1;
    if(t <= mid)
    {
        if(t >= segTree[rt<<1].r - segTree[rt<<1].rl + 1)
            return segTree[rt<<1].rl + query((rt<<1)|1, mid+1);
            //return query(rt<<1, t) + query((rt<<1)|1, mid+1);
        else
            return query(rt<<1, t);
    }
    else
    {
        if(t <= segTree[(rt<<1)|1].l + segTree[(rt<<1)|1].ll - 1)
            return segTree[(rt<<1)|1].ll + query(rt<<1, mid);
            //return query((rt<<1)|1, t) + query(rt<<1, mid);
        else
            return query((rt<<1)|1, t);
    }
}
int que[maxn];
int top;
int main()
{
    int n, m, x;
    char str[10];
    while(scanf("%d%d", &n, &m) != EOF)
    {
        top = 0;
        Build(1, 1, n);
        while(m--)
        {
            scanf("%s", str);
            if(str[0] == 'D')
            {
                scanf("%d", &x);
                que[top++] = x;
                update(1, x, 0);
            }
            else if(str[0] == 'Q')
            {
                scanf("%d", &x);
                printf("%d\n", query(1, x));
            }
            else
            {
                if(x > 0)
                {
                    x = que[--top];
                    update(1, x, 1);
                }
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值