zoukankan      html  css  js  c++  java
  • HDU 1540 Tunnel Warfare(线段树维护最大连续区间长度)

    题目大意:

    一段长为n的区间,m此操作,Q为查询x所在区间的最大长度,D为将X破坏(不连通),R为将最后一个破坏的点修复(连通)。

    题解思路:

    线段树,维护3个值。

    1.区间前缀长度

    2.区间后缀长度

    3.区间里最长连续区间

    用栈存储一下破坏的点,线段树的更新维护写在代码里;

    10001111 前缀为1 后缀为4;。

    维护前缀和后缀,是为了在归并和查询过程中维护连续区间长度。

    对于 0 0 0 1 1   1 1 1 0 1在归并中连续区间长度应为lson的后缀+rson的前缀

    在维护父节点前缀(后缀)时优先继承左孩子前缀(右孩子后缀),如果左孩子前缀(右孩子后缀)的长度等于区间长度应再加上右孩子前缀(左孩子后缀)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #include<stack>
    #include<algorithm>
    //被模板题搞自闭的蒟蒻
    #define lson rt<<1
    #define rson rt<<1|1
    
    const int maxn=1e5+10;
    
    using namespace std;
    
    struct node{
        int ls,rs,sum;
    }tree[4*maxn];
    //ls 前缀 rs 后缀 sum连续区间长度
    
    int n,m;
    
    void built(int l,int r,int rt)
    {
        int mid=(r+l)/2,sum=r-l+1;
        tree[rt]=(node){sum,sum,sum};
        if(l==r)
            return ;
        built(l,mid,lson);
        built(mid+1,r,rson);
    }
    
    void updata(int l,int r,int rt,int aim,int val)
    {
        if(l==r)
        {
            tree[rt].ls=tree[rt].rs=tree[rt].sum=val;
            return ;
        }
        int mid=(l+r)>>1;
        if(aim<=mid)
        {
            updata(l,mid,lson,aim,val);
        }
        if(aim>mid)
        {
            updata(mid+1,r,rson,aim,val);
        }
        tree[rt].ls=tree[lson].ls;//父节点继承左孩子的前缀
        tree[rt].rs=tree[rson].rs;
    
        if(tree[lson].ls==mid-l+1)//如果左孩子的前缀等于区间长度(左孩子满了)
            tree[rt].ls+=tree[rson].ls;//加上右孩子的前缀
        if(tree[rson].rs==r-mid)
            tree[rt].rs+=tree[lson].rs;
    
        tree[rt].sum=max(max(tree[lson].sum,tree[rson].sum),tree[lson].rs+tree[rson].ls);
        //父节点的sum为 左右孩子的最大值 与 左右孩子连起来的区间区最大值
        //            例如:110111 100111
    }
    
    int query(int l,int r,int rt,int aim)
    {
        if(l==r||tree[rt].sum==0||tree[rt].sum==l-r+1)
        {//如果到了叶子节点或者区间值等于0或区间长度直接返回即可
            return tree[rt].sum;
        }
        int mid=(l+r)>>1;
        if(aim<=mid)
        {
            if(aim>=mid-tree[lson].rs+1)
            //如果查询点在左孩子的后缀中
            //查询左孩子的长度加上右孩子的前缀
            //例如    0 0 0 1 1   1 1 1 0 1
            //             x
                return query(l,mid,lson,aim)+tree[rson].ls;
            else
            //否则只查询左孩子
                return query(l,mid,lson,aim);
        }
        else
        {
            if(aim<=mid+tree[rson].ls)
            //(mid+1)+tree[rson]-1
            //同上
            //  1 1 1 0 1   1 1 1 0 1
            //              x
                return query(mid+1,r,rson,aim)+tree[lson].rs;
            else
                return query(mid+1,r,rson,aim);
        }
    }
    
    int main(){
        while(~scanf("%d%d",&n,&m))
        {
            built(1,n,1);
            stack<int>q;
            while(m--)
            {
                char s[5];
                int now;
                scanf("%s",s);
                if(s[0]=='R')
                {
                    if(q.size())
                    {
                        updata(1,n,1,q.top(),1);
                        q.pop();
                    }
                }
                if(s[0]=='D')
                {
                    scanf("%d",&now);
                    q.push(now);
                    updata(1,n,1,now,0);
                }
                if(s[0]=='Q')
                {
                    scanf("%d",&now);
                    printf("%d
    ",query(1,n,1,now));
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    iOS 有用的代码片段
    iOS 限制软盘输入法
    UIlabel 遇到\n 换行iOS
    关于delegate 与 protocol 的理解 iOS
    ios 跳转到app store
    iOS 上下左右滑动手势
    求某段程序运行的高精度时间
    转载——GDB中应该知道的几个调试方法
    文章翻译——使用 GNU 的 GDB调试器,内存布局和栈——01
    第十章扩展——__cdecl 的压栈方式——printf
  • 原文地址:https://www.cnblogs.com/minun/p/10473770.html
Copyright © 2011-2022 走看看