• 洛谷 P3797 妖梦斩木棒


    https://www.luogu.org/problem/show?pid=3797

    题目背景

    妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力。

    题目描述

    有一天,妖梦正在练习剑术。地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段。现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’X’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’。幽幽子吃饱后闲来无事,决定戏弄一下妖梦。她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题。这些操作可以这样描述:

    1 x C 将第x个小段的木棒替换成C型,C只会是’X’,’(‘,’)’中的一种

    2 l r 询问妖梦从第l段到第r段之间(含l,r),有多少个完整的木棒

    完整的木棒左右两端必须分别为’(‘和’)’,并且中间要么什么都没有,要么只能有’X’。

    虽然妖梦能够数清楚这些问题,但幽幽子觉得她回答得太慢了,你能教给妖梦一个更快的办法吗?

    输入输出格式

    输入格式:

    第一行两个整数n,m,n表示共有n段木棒,m表示有m次操作。

    木棒的初始形状为(XXXXXX......XXXXXX)。

    接下来m行,每行三个整数/字符,用空格隔开。第一个整数为1或2,表示操作的类型,若类型为1,则接下来一个整数x,一个字符C。若类型为2,接下来两个整数l,r。含义见题目描述。

    输出格式:

    对于每一个操作2,输出一行一个整数,表示对应询问的答案。

    输入输出样例

    输入样例#1:
    4 4
    2 1 4
    2 2 4
    1 2 (
    2 2 4
    输出样例#1:
    1
    0
    1

    说明

    对于30%的数据,1<=n,m<=1000

    对于100%的数据,1<=n,m<=200000

    考虑了线段树,就不需要考虑形如(((XX)))怎么办

    因为线段树都是由底层一步一步合并上去的

    sum[k]=sum[l]+sum[r]+(左边最后是(,右边开始是))

    维护完整木棒数、区间最后边是否为(,区间最前边是否为)

    #include<cstdio>
    #define N 200001
    using namespace std;
    int sum[N<<2],mid[N<<2],num[N<<2];
    int ty[N];
    bool left[N<<2],right[N<<2];
    struct node
    {
        int tot,tot2;
        bool left,right;
        node() { left=right=false; tot=tot2=0;}
    };
    void build(int k,int l,int r)
    {
        if(l==r) return;
        mid[k]=l+r>>1;
        build(k<<1,l,mid[k]);
        build(k<<1|1,mid[k]+1,r);
    }
    void change(int k,int l,int r,int pos,int w)
    {
        if(l==r)
        {
            ty[pos]=w;
            left[k]=w==1 ? true : false;
            right[k]=w==2 ? true : false;
            if(w) num[k]=1; 
            else num[k]=0;
            return;
        }
        if(pos<=mid[k]) change(k<<1,l,mid[k],pos,w);
        else change(k<<1|1,mid[k]+1,r,pos,w);
        if(left[k<<1|1]) left[k]=true;
        else if(!num[k<<1|1] && left[k<<1]) left[k]=true;
        else left[k]=false;
        if(right[k<<1]) right[k]=true;
        else if(!num[k<<1] && right[k<<1|1]) right[k]=true;
        else right[k]=false;
        sum[k]=sum[k<<1]+sum[k<<1|1]+(left[k<<1] & right[k<<1|1]); 
        num[k]=num[k<<1]+num[k<<1|1];
    }
    node merge(node p,node q)
    {
        node res;
        res.tot=p.tot+q.tot+(p.left & q.right);
        res.tot2=p.tot2+q.tot2;
        if(q.left) res.left=true;
        else if(!q.tot2 && p.left) res.left=true;
        else res.left=false;
        if(p.right) res.right=true;
        else if(!p.tot2 && q.right) res.right=true;
        else res.right=false; 
        return res;
    }
    node query(int k,int l,int r,int opl,int opr)
    {
        if(l>=opl && r<=opr)
        {
            node res;
            res.left=left[k] ? true : false;
            res.right=right[k] ? true : false;
            res.tot=sum[k];
            res.tot2=num[k];
            return res;
        }
        if(opr<=mid[k]) return query(k<<1,l,mid[k],opl,opr);
        if(opl>mid[k]) return query(k<<1|1,mid[k]+1,r,opl,opr);
        return merge(query(k<<1,l,mid[k],opl,opr),query(k<<1|1,mid[k]+1,r,opl,opr));
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        build(1,1,n);
        change(1,1,n,1,1);
        change(1,1,n,n,2);
        int type,x,y;
        char c[2];
        while(m--)
        {
            scanf("%d%d",&type,&x);
            if(type==1) 
            {
                scanf("%s",c);
                if(c[0]=='X') y=0;
                else if(c[0]=='(') y=1;
                else y=2;
                change(1,1,n,x,y);
            }
            else 
            scanf("%d",&y),printf("%d
    ",query(1,1,n,x,y).tot);
        }
    }
  • 相关阅读:
    TCP粘包的拆包处理
    字节序列化
    同步,异步,阻塞和非阻塞
    用Doxygen生成文档
    Visual Studio新建的源文件的默认编码
    Boost编程之获取可执行文件的当前路径
    特征点寻找的基础数据结构和函数
    寻找Harris、Shi-Tomasi和亚像素角点
    特征点的基本概念和如何找到它们
    工业相机与普通相机的差别
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7485171.html
Copyright © 2020-2023  润新知