• 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;
    
    }
  • 相关阅读:
    Luogu 4206 [NOI2005]聪聪与可可
    【Luogu】P3708Koishi的数字游戏(数论)
    【Luogu】P1850换教室(期望DP)
    【Luogu】P1231教辅的组成(拆点+Dinic+当前弧优化)
    【Luogu】P3865ST表模板(ST表)
    【Luogu】P3376网络最大流模板(Dinic)
    【Luogu】P1005矩阵取数游戏(高精度+DP)
    【Luogu】P2324骑士精神(IDA*)
    【Luogu】P3052摩天大楼里的奶牛(遗传算法乱搞)
    洛森地图半成品
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3066009.html
Copyright © 2020-2023  润新知