题解:CF380C Sereja and Brackets

CF380C 题解

题面

原题传送门(洛谷)

原题传送门

题意

给定一个长度为 n 括号序列和 q 个询问区间 [l,r],对于每一个询问的区间中,要求出长度最长的为合法括号串的子串的长度。

思路

看到这种时间复杂度允许在 O(nlogn) 的,有许多区间的题目自然想到线段树。

但是进一步思考发现维护区间最大合法括号序列似乎有点困难,于是考虑利用正难则反的思想,考虑线段树每个节点维护的节点维护区间中不合法的左括号数 lsum 和不合法的右括号数 rsum

如果想到这一步的话,那这道题基本就解决了。

首先先考虑初始化。

对于线段树中的叶子结点,单独一个肯定是不合法的,所以有如下两种情况。

  • 若原序列中的位置为 (,则此节点 lsum1,rsum0
  • 若原序列中的位置为 ),则此节点 lsum0,rsum1

接下来考虑如何区间合并。

其实也很简单,左儿子区间和右儿子区间中原本单独拿出来不合法的括号数合并起来可以凑成 min(lsumls,rsumrs) 对合法的括号,所以在合并的区间中,左右括号的不合法数就要减去它,所以就有。

  • lsumplsumls+lsumrsmin(lsumls,rsumrs)

  • rsumprsumls+rsumrsmin(lsumls,rsumrs)

(其中 p 是当前节点的编号。)

统计答案的时候也是同样的道理,最后输出询问区间的长度减去不合法括号数即可。

于是,就可以过了这道题啦。

代码

AC记录

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int MN=1e6+5;
ll n,q;
struct tree{
    ll lsum,rsum,l,r;
    void clear(){lsum=rsum=0;}
}t[MN<<2];
char ch[MN];
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
void update(ll p){
    ll num=min(t[ls].lsum,t[rs].rsum);
    t[p].lsum=t[ls].lsum+t[rs].lsum-num;
    t[p].rsum=t[ls].rsum+t[rs].rsum-num;
}
void build(ll p, ll l, ll r){
    t[p].l=l;t[p].r=r;
    if(l==r){
        if(ch[l]=='(') t[p].lsum=1;
        else t[p].rsum=1;
        return;
    }
    ll mid=l+r>>1;
    build(ls,l,mid);build(rs,mid+1,r);
    update(p);
}
tree query(ll p, ll l, ll r){
    if(l<=t[p].l&&t[p].r<=r) return t[p];
    ll mid=(t[p].l+t[p].r)>>1;tree res;res.clear();
    if(r<=mid) return query(ls,l,r);
    if(l>mid) return query(rs,l,r);
    tree lc=query(ls,l,r),rc=query(rs,l,r);
    ll num=min(lc.lsum,rc.rsum);
    res.lsum=lc.lsum+rc.lsum-num;
    res.rsum=lc.rsum+rc.rsum-num;
    return res;
}
int main(){
    scanf("%s",ch+1);n=strlen(ch+1);
    build(1,1,n);
    q=read();while(q--){
        ll l=read(),r=read();
        tree ans=query(1,l,r);
        write((r-l+1)-ans.lsum-ans.rsum);putchar('\n');
    }
    return 0;
}
posted @   naroto2022  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
花开如火,也如寂寞。