洛谷 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\n",query(1,1,n,x,y).tot);
    }
}

 

posted @ 2017-09-06 15:48  TRTTG  阅读(353)  评论(0编辑  收藏  举报