【线段树,栈】Day 7 提高组模拟C组 T2 圣章-精灵使的魔法语

题目描述

2

解题思路

40分思想:
因为右括号能够盖住左括号,所以当右括号的个数超过左括号时,其就会需要多一个括号进行匹配,再加上每个括号会与距离其最近的括号匹配,所以这是一个先进后出的结构,所以我们可以用栈解决,时间复杂度 O ( n m )
100分思路:
上一种思路之所以慢是因为它每次都要一遍循环找括号,然后由于令人讨厌的单点修改,于是构成了区间查询和单点修改与信息维护,这时我们可以用到一个骚气的东西线段树!
用线段树维护括号数就可以达到快速求解的目的了,时间复杂度 O ( m l o g n )
注意,若您线段树的代码超时了,您可以在https://blog.csdn.net/xuxiayang/article/details/81021585获得一些经验

40分代码

#include<stack>
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,x,y,l,r,ansl,ansr;
char c[150001],q[101];
stack<char>s;
int main()
{
    freopen("elf.in","r",stdin);
    freopen("elf.out","w",stdout);
    cin>>n>>m>>c+1;
    while(m--)
    {
        cin>>q;
        if(q[0]=='Q')
        {
            cin>>x>>y;
            while(s.size()) s.pop();
            if(x==y) {if(c[x]=='(') printf("0 1\n");else printf("1 0\n");continue;}
            ansl=0;ansr=0;
            for(int i=x;i<=y;i++)
             if(c[i]=='(') s.push(c[i]);//左括号入栈
             else
             {
                if(s.size()) s.pop();//出栈=抵消
                else ansl++;//没有抵消说明多出了一个右括号,那么我们需要新增一个左括号维护
             }
             ansr=s.size();//若栈中还有元素,说明还有左括号未被匹配,则需要加上该数量的右括号
            printf("%d %d\n",ansl,ansr);
        }
        else
        {
            cin>>x;
            if(c[x]=='(') c[x]=')';
            else c[x]='(';
        }
    }
}

AC代码

#include<iostream>
#include<cstdio>
#define lson k<<1
#define rson k<<1|1
using namespace std;int n,m,x,y,ansl,ansr,f;
char c[150001],q[51],ask;
struct node{int l,r,lm,rm;}t[600001];
void write(int x)//输出流
{
    if(x>9) write(x/10);putchar(x%10+48);
    return;
}
void judge(node &k,node &x,node &y)//合并,传递信息
{
    k.lm=y.lm+max(0,x.lm-y.rm);
    k.rm=x.rm+max(0,y.rm-x.lm);
    return;
}
void build(int k,int l,int r)//建树
{
    t[k].l=l;t[k].r=r;
    if(l==r)
    {
        t[k].lm=c[l]=='('?1:0;
        t[k].rm=c[l]==')'?1:0;//初始化
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    judge(t[k],t[lson],t[rson]);//传递信息
    return;
}
void add(int k,int x)
{
    if(t[k].l==x&&t[k].r==x)
    {
        t[k].lm^=1;
        t[k].rm^=1;//取反=单点修改
        return;
    }
    if(t[k].l==t[k].r) return;//到达叶子节点结束
    int mid=(t[k].l+t[k].r)>>1;
    if(x<=mid) add(lson,x);else add(rson,x);
    judge(t[k],t[lson],t[rson]);//传递信息
    return;
}
node query(int k,int x,int y)
{
    if(t[k].l==x&&t[k].r==y) return t[k];//到达目标区间传递信息返回
    if(t[k].l==t[k].r) return (node){t[k].l,t[k].r,0,0};//到达叶子节点返回空
    int mid=(t[k].l+t[k].r)>>1;
    if(y<=mid) return query(lson,x,y);
    if(x>mid) return query(rson,x,y);
    node ls,rs,ans;
    ls=query(lson,x,mid);//访问左区间
    rs=query(rson,mid+1,y);//访问右区间
    judge(ans,ls,rs);//合并,传递信息
    return ans;
}
int main()
{
    freopen("elf.in","r",stdin);
    freopen("elf.out","w",stdout);
    scanf("%d%d",&n,&m);
    scanf("%s",c+1);
    build(1,1,n);
    while(m--)
    {
        scanf("%s %d",q,&x);
        if(q[0]=='Q')
        {
            scanf("%d",&y);
            node ans=query(1,x,y);//查询
            write(ans.rm);putchar(32);write(ans.lm);putchar(10);//输出
        }
        else add(1,x);//修改
    }
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/81021116