• 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;
    
    }
  • 相关阅读:
    Asp.Net Winform 条形码系列之Code39 Code39 Of .Net BarCode Serial Blog
    .NET 中文星期几的简单实现方式
    C#使用SQLite数据库(asp.net/winform)
    .Net日期时间格式化输出大全 DateTime.ToString(?)
    C#使用HTTP头检测网络资源是否有效
    [转]C#(VB.NET)操作Windows自带的防火墙 之 添加/删除允许通过防火墙的例外程序
    华为C2800进入工程模式
    android webview 加载网页显示对话框
    SVN 与 VS2003
    VisualSVN1.7.7 序列号
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3066009.html
Copyright © 2020-2023  润新知