• 蓝桥杯 翻转括号序列 题解(线段树 思维)


    题目链接

    题目大意

    给定一个长度为 \(n\) 的括号序列,要求支持两种操作:

    1. \([L,R]\) 区间内的括号全部翻转
    2. 求出以\(L\)为左端点时,最长的合法括号序列对应的\(R\)

    \(1 ≤ n ≤ 10^6 , 1 ≤ m ≤ 2 × 10^5\)

    题目思路

    首先根据这个数据范围,要想到线段树

    \(s[i]==( \;a[i]=1\)

    \(s[i]==) \;a[i]=-1\)

    一个显然的想法是建立一个线段树,其节点的值为\(a\)数组的前缀和

    那么对于操作\(1\)如何修改是一个问题,你会发现不好直接进行修改

    可以把这个问题转化为\([1,l-1]\)\([1,r]\)修改两次,显然是等价的

    那么修改\([1,x]\)会使得\([1,x]\)中的元素乘以\(-1\),使得\([x+1,n]\)中的所有元素\(+2pre[x]\)

    对于操作2显然是要找到在\([l,n]\)中找到一个最大的\(pos\)使得\(pre[pos]==pre[l-1]\)

    并且在\([l,pos-1]\)中不存在\(pre[i]<pre[pos]\)

    这个问题比较麻烦,解决的方法也比较巧妙

    首先找到\([l,n]\)中第一个小于\(pre[l-1]\)\(pos\),那么答案必定在\([l,pos-1]\)

    再找到\([1,pos-1]\)中坐标最接近\(pos-1\)且值小于\(pre[l-1]+1\)的位置

    如果这个位置大于\(l\)显然就是答案,否则为\(0\)

    如何寻找\(pos\)就是线段树上二分,需要维护区间的最大最小值

    这个题目要关注的是有两个\(lazy\)相互影响要注意写法

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,m;
    int a[maxn];
    int mi[maxn<<2],ma[maxn<<2];
    int lazy[maxn<<2][3];
    char s[maxn];
    void updown(int node){
        if(lazy[node][1]){
            lazy[node<<1][1]^=1;
            lazy[node<<1|1][1]^=1;
            swap(mi[node<<1],ma[node<<1]);
            mi[node<<1]*=-1,ma[node<<1]*=-1;
            swap(mi[node<<1|1],ma[node<<1|1]);
            mi[node<<1|1]*=-1,ma[node<<1|1]*=-1;
            // 一定要写下面这句话 加的东西也发生了改变
            lazy[node<<1|1][2]*=-1;
            lazy[node<<1][2]*=-1;
            lazy[node][1]=0;
        }
        if(lazy[node][2]){
            lazy[node<<1][2]+=lazy[node][2];
            lazy[node<<1|1][2]+=lazy[node][2];
            mi[node<<1]+=lazy[node][2],ma[node<<1]+=lazy[node][2];
            mi[node<<1|1]+=lazy[node][2],ma[node<<1|1]+=lazy[node][2];
            lazy[node][2]=0;
        }
    }
    void push_up(int node){
        mi[node]=min(mi[node<<1],mi[node<<1|1]);
        ma[node]=max(ma[node<<1],ma[node<<1|1]);
    }
    void build(int node,int l,int r){
        if(l==r){
            mi[node]=ma[node]=a[l];
            return ;
        }
        int mid=(l+r)/2;
        build(node<<1,l,mid);
        build(node<<1|1,mid+1,r);
        push_up(node);
    }
    void update(int node,int L,int R,int l,int r,int add,int op){
        if(L>R) return ;
        // 边界处理
        if(L<=l&&r<=R){
            if(op==1){
                swap(mi[node],ma[node]);
                mi[node]*=-1;
                ma[node]*=-1;
                lazy[node][op]^=1;
                // 一定要写下面这句话 加的东西也发生了改变
                lazy[node][2]*=-1;
            }else if(op==2){
                mi[node]+=add;
                ma[node]+=add;
                lazy[node][op]+=add;
            }
            return ;
        }
        updown(node);
        int mid=(l+r)/2;
        if(mid>=L) update(node<<1,L,R,l,mid,add,op);
        if(mid<R)  update(node<<1|1,L,R,mid+1,r,add,op);
        push_up(node);
    }
    int query(int node,int l,int r,int pos){
        if(pos==0||pos==n+1){// 边界处理
            return 0;
        }
        if(l==r){
            return ma[node];
        }
        updown(node);
        int mid=(l+r)/2,now=0;
        if(mid>=pos) now=query(node<<1,l,mid,pos);
        if(mid<pos)  now=query(node<<1|1,mid+1,r,pos);
        return now;
    }
    int query_serch1(int node,int l,int r,int pos,int val){
        if(l==r){
            return l;
        }
        int mid=(l+r)/2;
        int ans=0;
        updown(node);
        if(mid>=pos&&mi[node<<1]<val){
            ans=query_serch1(node<<1,l,mid,pos,val);
        }
        if(ans==0&&mi[node<<1|1]<val){
            ans=query_serch1(node<<1|1,mid+1,r,pos,val);
        }
        return ans;
    }
    int query_serch2(int node,int l,int r,int pos,int val){
        if(l==r){
            return l;
        }
        int mid=(l+r)/2;
        int ans=0;
        updown(node);
        if(mid+1<=pos&&mi[node<<1|1]<val){
            ans=query_serch2(node<<1|1,mid+1,r,pos,val);
        }
        if(ans==0&&mi[node<<1]<val){
            ans=query_serch2(node<<1,l,mid,pos,val);
        }
        return ans;
    }
    signed main(){
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for(int i=1;i<=n;i++){
            if(s[i]=='(') a[i]=1;
            else a[i]=-1;
            a[i]+=a[i-1];
        }
        build(1,1,n);
        for(int i=1,opt,l,r;i<=m;i++){
            scanf("%d%d",&opt,&l);
            if(opt==1){
                scanf("%d",&r);
                // [1,l-1]
                update(1,1,l-1,1,n,0,1);
                int sum=query(1,1,n,l-1);
                update(1,l,n,1,n,2*sum,2);
                // [1,r]
                update(1,1,r,1,n,0,1);
                sum=query(1,1,n,r);
                update(1,r+1,n,1,n,2*sum,2);
            }else{
                int sum=query(1,1,n,l-1);// 要找pre[l-1]
                int lim=query_serch1(1,1,n,l,sum);
    
                // 找到[l,n]中第一个比sum小的值
                if(lim==0) lim=n+1;
                // 找到[1,lim-1]中比sum+1小最接近lim-1的值
                int ans=query_serch2(1,1,n,lim-1,sum+1);
                if(ans>l){
                    printf("%d\n",ans);
                }else{
                    printf("0\n");
                }
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    Mybatis的缓存
    Mybatis使用assocation和Collection实现延迟加载
    Mybatis:一对多的查询
    Mysql:事务
    Mysql:多表查询
    Mysql:数据库的设计
    Mysql:约束
    MYSQL:DQL-查询表中的记录
    panic: cannot create context from nil parent
    $request input 获取参数null
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15937318.html
Copyright © 2020-2023  润新知