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;



}

 

你可能感兴趣的:(HDU)