HDU 1540 Tunnel Warfare(线段树 区间合并 +单点更新)

/*
题意:先给定一段区间,都是可用的,然后给出一些操作,有恢复的,有毁坏的,有查询的,查询包含那个点的最长区间
题目分类 线段树 单点更新 区间合并

*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=50005,inf=1<<29;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];
int col[maxn<<2];
void PushUp(int rt,int m)//利用子节点信息更新父节点
{
    lsum[rt]=lsum[rt<<1];//根节点从左边其的最长区间至少等于左儿子从左边起得最长区间
    rsum[rt]=rsum[rt<<1|1];
    if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
    if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1];
    msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);
}
void build(int l,int r,int rt)//建树
{
    col[rt]=0;//单点更新根本没必要用延迟标记。。。
    if(l==r)
    {
        lsum[rt]=rsum[rt]=msum[rt]=1;
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt,r-l+1);
}
void update(int p,int x,int l,int r,int rt)//单点更新
{
    if(l==r)
    {
        lsum[rt]=rsum[rt]=msum[rt]=x?0:1;
        return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,x,lson);
    else update(p,x,rson);
    PushUp(rt,r-l+1);
}
int Query(int x,int l,int r,int rt)
{
    //区间是叶子节点或都可用或都不可用直接返回
    if(l==r||msum[rt]==0||msum[rt]==r-l+1) return msum[rt];
    int ans=0;
    int m=(l+r)>>1;
    if(x<=m)//如果要查的点在左子树
    {
        //如果左子树的区间右端减去-从右起最大的连续区间大于等于当前点,那么当前点所在的连续区间可以与右子树从左边起得最长区间合并
        if(x>=(m-rsum[rt<<1]+1)) return Query(x,lson)+Query(m+1,rson);
        return Query(x,lson);
    }
    if(x<=m+1+lsum[rt<<1|1]-1) return Query(m,lson)+Query(x,rson);
    return Query(x,rson);
}
int main()
{
     //freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
     //srand(time(NULL));
     int n,m,x;
    while(~scanf("%d%d",&n,&m))
    {
        stack<int>st;
        char op[5];
        build(1,n,1);
        for(int i=0;i<m;i++)
        {
            scanf("%s%d",op,&x);
            if(op[0]=='D')
            {
                update(x,1,1,n,1);
                st.push(x);
            }
            else if(op[0]=='R')
            {
                if(st.size())
                {
                    x=st.top();
                    st.pop();
                    update(x,0,1,n,1);
                }
            }
            else printf("%d\n",Query(x,1,n,1));
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值