hdu 1540 Tunnel Warfare

题目链接如下所示:

Problem - 1540

这题的意思其实是用线段树维护一个连续区间和。

我们用lsum和rsum代表节点的最左连续区间和,最右区间连续区间和。

那么在push_up的时候我们要做的就是根据孩子节点的区间和更新当前根节点的区间和。如果是等于了左右区间的话,说明是可以扩展的区间和,也就是可以继续扩大。

对于D操作,我们简单update对应位置的值变成0。

对于R操作,我们将上一个update的位置的值变成1。

对于Q操作,我们的目标是找到对应位置的最长连续区间和。假设当前的点代表的区间是[l,r],要询问的位置是pos,那么当前左右区间长度我们设为pos-l+1和r-pos+1,若lsum或者rsum大于等于这个区间的长度,我们就判断找到对应区间的一部分,返回对应连续区间和。由于这个区间肯定是可扩展的,所以我们直接返回的那一次结果还要加上另外一个区间的邻接的连续区间和。并且在这之后的返回过程中不需要更新,因为如果还存在可以相连的连续区间,递归返回的层数和这个就不一样了,会产生矛盾。

代码如下所示:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cmath>
#include<climits>

using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAXN=50001;
int lsum[MAXN<<2],rsum[MAXN<<2];
int flag;

void push_up(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];
}

void build(int l,int r,int rt){
    if (l==r){
        lsum[rt]=rsum[rt]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt, r-l+1);
}

void update(int pos,int val,int l,int r,int rt){
    if (l==r){
        lsum[rt]=rsum[rt]=val;
        return;
    }
    int mid=(l+r)>>1;
    if (pos<=mid){
        update(pos,val,lson);
    } else{
        update(pos,val,rson);
    }
    push_up(rt,r-l+1);
}

int query(int pos,int l,int r,int rt){
    if (rsum[rt]>=r-pos+1){
        flag=1;
        return rsum[rt];
    }
    if (lsum[rt]>=pos-l+1){
        flag=1;
        return lsum[rt];
    }
    if (l==r) return 0;
    int res;
    int mid=(l+r)>>1;
    if (pos<=mid){
        res=query(pos,lson);
        if (flag){
            flag=0;
            res+=lsum[rt<<1|1];
        }
    } else{
        res=query(pos,rson);
        if (flag){
            flag=0;
            res+=rsum[rt<<1];
        }
    }
    return res;
}

int main(){
    int n,m,pos;
    while (~scanf("%d %d",&n,&m)){
        stack<int> st;
        build(1,n,1);
        char op[2];
        for (int i = 0; i < m; ++i) {
            scanf("%s",op);
            if (op[0]=='D'){
                scanf("%d",&pos);
                st.push(pos);
                update(pos,0,1,n,1);
            }else if (op[0]=='Q'){
                scanf("%d",&pos);
                flag=0;
                printf("%d\n", query(pos,1,n,1));
            }else{
                update(st.top(),1,1,n,1);
                st.pop();
            }
        }
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值