P3797 妖梦斩木棒 线段树区间合并

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3797 妖梦斩木棒 线段树区间合并相关的知识,希望对你有一定的参考价值。

题意:

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

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

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

题解:
典型的线段树维护区间合并问题 (特别注意query中的合并)
开三个数组,ls代表左端是否拥有右括号,rs代表右端是否有左括号,ishave用来代表区间中是否有括号。

代码:

#include<bits/stdc++.h>
#define endl '\\n'
using namespace std;

const int maxn=1e6+10;

int sum[maxn];
int ls[maxn],rs[maxn];
int ishave[maxn];
void push_up(int node){

    sum[node]=sum[node<<1]+sum[node<<1|1];
    if(ls[node<<1|1]==1&&rs[node<<1]==1){
        sum[node]++;
    }
    ishave[node]=ishave[node<<1]|ishave[node<<1|1];
    if((ls[node<<1|1]&&!ishave[node<<1])||ls[node<<1]) ls[node]=1;
    else ls[node]=0;
    if((rs[node<<1]&&!ishave[node<<1|1])||rs[node<<1|1]) rs[node]=1;
    else rs[node]=0;
}
void update(int node,int start,int ends,int pos,char c){
    if(start==ends){
        if(c=='(') rs[node]=1,ls[node]=0,ishave[node]=1;
        if(c==')') ls[node]=1,rs[node]=0,ishave[node]=1;
        if(c=='X') ls[node]=rs[node]=ishave[node]=0;
        return ;
    }
    int mid=(start+ends)>>1;
    if(pos<=mid) update(node<<1,start,mid,pos,c);
    else update(node<<1|1,mid+1,ends,pos,c);
    push_up(node);
}

int query(int node,int start,int ends,int l,int r,int &L,int &R){
    if(l<=start&&ends<=r){
        if(rs[node]) R=1;
        else R=0;
        if(ls[node]) L=1;
        else L=0;
        return sum[node];
    }
    int mid=(start+ends)>>1;
    int res=0;
    int LL=-1,RR=-1,LR=-1,RL=-1;
    if(l<=mid)  res+=query(node<<1,start,mid,l,r,LL,LR);
    if(mid<r) res+=query(node<<1|1,mid+1,ends,l,r,RL,RR);
    if(RR||(LR==1&&!ishave[node<<1|1])) R=1;
    else R=0;
    if(LL||(!ishave[node<<1]&&RL==1)) L=1;
    else L=0;
    if((LR==1&&RL==1)) res++;
    return res;
}
int main(){
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
//    freopen("P3797_1.in","r",stdin);
//    freopen("P3797_1.out","w",stdout);
    int n,m;
    cin>>n>>m;
    update(1,1,n,1,'(');
    update(1,1,n,n,')');
    while(m--){
        int opt;
        cin>>opt;
        if(opt==1){
            int x;
            char c;
            cin>>x>>c;
            update(1,1,n,x,c);
        }
        else{
            int l,r;
            cin>>l>>r;
            int x=0,y=0;
            cout<<query(1,1,n,l,r,x,y)<<endl;
        }
    }
}

以上是关于P3797 妖梦斩木棒 线段树区间合并的主要内容,如果未能解决你的问题,请参考以下文章

[luogu P3797] 妖梦斩木棒 [线段树]

AC日记——妖梦斩木棒 洛谷 P3797

洛谷P3797 妖梦斩木棒

洛谷 P3797 妖梦斩木棒

仍是下次写

妖梦斩木棒