HDU 1540(线段树区间合并)

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

 

题目大意:三种操作,D销毁一个城市,R复活最近摧毁的一个城市,Q询问x所在城市所在的连续存活城市长度。

 

题目思路:1表示存活,0表示摧毁,则求得就是x所在的1的长度。维护三个量,线段中最左边1的长度,线段中最右边1的长度,线段中最长的1的长度,分别用l1,r1,m1表示。所以更新时,大的段的最左边1的长度就是他的左半边的最左边1长度,如果左半边全是1的话,那么就是最左边长度加右半边的最左边1长度。最右同理。最大的量就是左半边和最右边m1取max,接着再跟左半边的最右边1长度+右半边的最左边1长度取max就是m1。然后是查询。查询的话如果x在mid的左边,判断他在不在左半边的最右连续1中,在的话要跟右半边的左半边1进行合并,不在就直接继续管左边。这里需要注意,return query(rt<<1,x)+query(rt<<1|1,mid+1);,后面返回的是mid+1,不是x了。

 

以下是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const ll MAXN = 5e4+5;
const ll MOD = 1e9+7;
char cmd[10];
stack<int>s;
struct node{
    int l,r,l1,r1,m1;
}a[MAXN<<2];
void build(int rt,int l,int r){
    a[rt].l=l,a[rt].r=r;
    a[rt].l1=a[rt].r1=a[rt].m1=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 x,int val){
    if(a[rt].l == x && a[rt].r == x){
        a[rt].l1 =  a[rt].r1 =  a[rt].m1 = val;
        return;
    }
    int mid=(a[rt].l + a[rt].r)>>1;
    if(x <= mid)update(rt<<1,x,val);
    if(x > mid)update(rt<<1|1,x,val);
    a[rt].l1 = a[rt<<1].l1 , a[rt].r1 = a[rt<<1|1].r1;
    a[rt].m1 = max(a[rt<<1].m1, a[rt<<1|1].m1);
    a[rt].m1=max(a[rt].m1,a[rt<<1].r1 + a[rt<<1|1].l1);
    if(a[rt<<1].l1==a[rt<<1].r-a[rt<<1].l+1)a[rt].l1 += a[rt<<1|1].l1;
    if(a[rt<<1|1].r1==a[rt<<1|1].r-a[rt<<1|1].l+1)a[rt].r1 += a[rt<<1].r1;
}
int query(int rt,int x){
    if(a[rt].l==a[rt].r||a[rt].m1==0||a[rt].m1==a[rt].r-a[rt].l+1){
        return a[rt].m1;
    }
    int mid=(a[rt].l+a[rt].r)>>1;
    if(x<=mid){
        if(a[rt<<1].r-a[rt<<1].r1 + 1 <= x)return query(rt<<1,x)+query(rt<<1|1,mid+1);
        return query(rt<<1,x);
    }
    else{
        if(a[rt<<1|1].l + a[rt<<1|1].l1 - 1 >= x)return query(rt<<1,mid)+query(rt<<1|1,x);
        return query(rt<<1|1,x);
    }
}
int main(){
    int n,m,x;
    while(~scanf("%d%d",&n,&m)){
        while(!s.empty())s.pop();
        build(1,1,n);
        while(m--){
            scanf("%s",cmd);
            if(cmd[0]=='D'){
                scanf("%d",&x);
                update(1,x,0);
                s.push(x);
            }
            if(cmd[0]=='R'){
                int temp=s.top();
                s.pop();
                update(1,temp,1);
            }
            if(cmd[0]=='Q'){
                scanf("%d",&x);
                int ans=query(1,x);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值