hdu 1540 Tunnel Warfare

线段树

题意:一个长度为n的线段,下面m个操作

D x 表示将单元x毁掉

R  表示修复最后毁坏的那个单元

Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0

 

要记录单元被损坏的顺序,用一个栈就好了,毁坏就入栈,修复就出栈

说说思路,最难的是查询一个点附近有那些的连接着的区间

这需要在线段树记录三个信息,tlen,llen,rlen,这个记录和 poj 3667 Hotel 记录的意义是相同的 , tlen表示该节点内最长的可用区间的长度,llen表示最左端数起的区间长度,rlen表示从最右端数起的区间长度

对于一个点,看它是在当前区间的左半还是右半

在左半的话,看看是不是在右端的连续区间内,是的话,还要加上右半区间的左端连续区间。否则的话,只要计算它在左半区间的连接情况即可

在右半的话同理,看看是不是在左端的连续区间内,是的话,还要加上左半区间的右端连续区间。否则的话,只要计算它在右半区间的连接情况即可

 

所以需要时刻维护好每个节点的tlen,llen,rlen,在updata函数中,和 poj 3667 Hotel 的维护是一样的

 

 

#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define lch(i) ((i)<<1)
#define rch(i) ((i)<<1|1)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 50010

struct node
{
    int l,r;
    int mark;
    int tlen,llen,rlen;
    int mid(){
        return (l+r)>>1;
    }
    int cal_len(){
        return r-l+1;
    }
    void updata_len(){
        tlen = llen = rlen = (mark ? 0 : cal_len());
    }
}t[4*N];

void build(int l , int r , int rt)
{
    t[rt].l = l; t[rt].r = r; 
    t[rt].mark = 0;
    t[rt].tlen = t[rt].llen = t[rt].rlen = t[rt].cal_len();
    if(l == r) return ;
    int mid = t[rt].mid();
    build(l , mid , lch(rt));
    build(mid+1 , r , rch(rt));
    return ;
}

void updata(int pos ,int val ,int rt)
{
    if(t[rt].l == t[rt].r)
    {
        t[rt].mark = val;
        t[rt].updata_len();
        return ;
    } 
    if(t[rt].mark != -1)
    {
        t[lch(rt)].mark = t[rch(rt)].mark = t[rt].mark;
        t[rt].mark = -1;
        t[lch(rt)].updata_len();
        t[rch(rt)].updata_len();
    }
    int mid = t[rt].mid();
    if(pos <= mid) //在左半
        updata(pos , val , lch(rt));
    else //在右半
        updata(pos , val , rch(rt));

    int temp = max(t[lch(rt)].tlen , t[rch(rt)].tlen);
    t[rt].tlen = max(temp , t[lch(rt)].rlen + t[rch(rt)].llen);
    t[rt].llen = t[lch(rt)].llen;
    t[rt].rlen = t[rch(rt)].rlen;
    if(t[lch(rt)].tlen == t[lch(rt)].cal_len())
        t[rt].llen += t[rch(rt)].llen;
    if(t[rch(rt)].tlen == t[rch(rt)].cal_len())
        t[rt].rlen += t[lch(rt)].rlen;
    return ;
}

int query(int pos , int rt)
{
    if(t[rt].l == t[rt].r || t[rt].tlen == 0 || t[rt].tlen == t[rt].cal_len())
        return t[rt].tlen;
    //上面的部分可以改变一下写法,看看时间会不会有明显的变化
    
    if(t[rt].mark != -1)
    {
        t[lch(rt)].mark = t[rch(rt)].mark = t[rt].mark;
        t[rt].mark = -1;
        t[lch(rt)].updata_len();
        t[rch(rt)].updata_len();
    }
    int mid = t[rt].mid();
    if(pos <= mid) //查询的点在左边 
    {
        int index = mid-t[lch(rt)].rlen+1;
        if(index <= pos) //包含在内
            return query(pos , lch(rt)) + query(mid+1 , rch(rt));
        else
            return query(pos , lch(rt));
    }
    else
    {
        int index = mid+t[rch(rt)].llen;
        if(pos <= index) //包含在内
            return query(mid , lch(rt)) + query(pos , rch(rt));
        else
            return query(pos , rch(rt));
    }
}

int main()
{
    int n,m;
    stack<int>sta;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n,1);
        while(!sta.empty()) sta.pop();
        while(m--)
        {
            char op[5];
            int pos , len;
            scanf("%s",op);
            if(op[0] == 'R')
            {
                if(sta.empty()) continue;
                int pos = sta.top();
                sta.pop();
                updata(pos , 0 , 1);
            }
            else if(op[0] == 'D')
            {
                scanf("%d",&pos);
                sta.push(pos);
                updata(pos , 1 , 1);
            }
            else
            {
                scanf("%d",&pos);
                len = query(pos,1);
                printf("%d\n",len);
            }
        }
    }
    return 0;

}

 

posted @ 2013-05-07 23:38  Titanium  阅读(1330)  评论(1编辑  收藏  举报