HDU1540-Tunnel Warfare-线段树区间合并

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

这个题目是个区间合并的模板题,但是有一点不同的是分两步查询思路很清晰;

这里有一个博客写的不错,我就不再赘述了;链接:http://blog.csdn.net/xingyeyongheng/article/details/11619461

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
#define inf 1<<30
#define s(a,b) scanf("%d%d",&a,&b)
#define Clear(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=50015;
int n,m,a,b,ch;
int num[N];     //  该数组记录被损坏的村庄;
int ls[N<<2],rs[N<<2];  //  分别存左右端点起的最大长度;
void PushUp(int rt,int m)
{
    ls[rt]=ls[rt<<1];
    rs[rt]=rs[rt<<1|1];
    if(ls[rt]==m-(m>>1)) ls[rt]+=ls[rt<<1|1];   //  左儿子区间最大长度为整个区间,需要拼接右儿子区间左端点起的最长长度;
    if(rs[rt]==m>>1) rs[rt]+=rs[rt<<1];         //  右儿子区间最大长度为整个区间,同理;
}
void Build(int l,int r,int rt)
{
    ls[rt]=rs[rt]=r-l+1;    //  初始化为最长长度;
    if(l!=r){
        int mid=(l+r)>>1;
        Build(l,mid,rt<<1);
        Build(mid+1,r,rt<<1|1);
    }
}
void Updata(int p,int v,int l,int r,int rt)
{
    if(l==r){
        ls[rt]=v;
        rs[rt]=v;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid) Updata(p,v,l,mid,rt<<1);
    else Updata(p,v,mid+1,r,rt<<1|1);
    PushUp(rt,r-l+1);
}
int QueryL(int L,int R,int l,int r,int rt)  //  返回右边左区间最大长度;
{
    if(L<=l&&r<=R) return ls[rt];
    int mid=(l+r)>>1;
    if(R<=mid) return QueryL(L,R,l,mid,rt<<1);
    else if(L>mid) return QueryL(L,R,mid+1,r,rt<<1|1);
    else{
        int lans=QueryL(L,mid,l,mid,rt<<1);
        int rans=QueryL(mid+1,R,mid+1,r,rt<<1|1);
        if(lans==mid-L+1) return lans+rans;
        else return lans;
    }
}
int QueryR(int L,int R,int l,int r,int rt)  //  返回左边右区间最大长度;
{
    if(L<=l&&r<=R) return rs[rt];
    int mid=(l+r)>>1;
    if(R<=mid) return QueryR(L,R,l,mid,rt<<1);
    else if(L>mid) return QueryR(L,R,mid+1,r,rt<<1|1);
    else{
        int lans=QueryR(L,mid,l,mid,rt<<1);
        int rans=QueryR(mid+1,R,mid+1,r,rt<<1|1);
        if(rans==R-mid) return lans+rans;
        return rans;
    }
}
int main()
{
    //freopen("../../in.txt","r",stdin);
    //freopen("../../out.txt","w",stdout);
    while(~s(n,m)){
        Build(1,n,1);
        int top=0;
        while(m--){
            scanf(" %c",&ch);
            if(ch=='D'){
                scanf("%d",&a);
                num[top++]=a;
                Updata(a,0,1,n,1);
            }else if(ch=='R'&&top>0){   //  top>0说明还有被损坏的村庄;
                int a=num[--top];
                Updata(a,1,1,n,1);
            }else if(ch=='Q'){
                scanf("%d",&a);
                int ans=QueryL(a,n,1,n,1)+QueryR(1,a,1,n,1);
                printf("%d\n",ans>0?ans-1:0);
            }
        }
    }
    return 0;
}


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值