【BZOJ2329】括号修复(Splay)

232 篇文章 0 订阅
13 篇文章 0 订阅

题面

BZOJ
洛谷

题解

本来想着用线段树来写
但是有一个区间翻转
所以不能用线段树了,就只能用平衡树
然后直接 Splay 就好了
注意一下几个标记的下放问题
这种数据结构真的没有什么思路可言。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
#define ls (t[x].ch[0])
#define rs (t[x].ch[1])
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node
{
    int ch[2],ff,size;
    int lm,rm,lg,rg,sum,v;
    int rev,eql,inv;
}t[MAX];
int rt;
void pushup(int x)
{
    t[x].lm=max(t[ls].lm,t[ls].sum+t[x].v+t[rs].lm);
    t[x].rm=max(t[rs].rm,t[rs].sum+t[x].v+t[ls].rm);
    t[x].lg=min(t[ls].lg,t[ls].sum+t[x].v+t[rs].lg);
    t[x].rg=min(t[rs].rg,t[rs].sum+t[x].v+t[ls].rg);
    t[x].sum=t[ls].sum+t[rs].sum+t[x].v;
    t[x].size=t[ls].size+t[rs].size+1;
}
void rotate(int x)
{
    int y=t[x].ff,z=t[y].ff;
    int k=t[y].ch[1]==x;
    if(z)t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;t[y].ff=x;
    pushup(y);
}
void putrev(int x)
{
    if(!x)return;
    swap(t[x].lg,t[x].rg);
    swap(t[x].lm,t[x].rm);
    swap(ls,rs);t[x].rev^=1;
}
void putinv(int x)
{
    if(!x)return;
    t[x].v*=-1;t[x].inv^=1;t[x].sum*=-1;
    swap(t[x].lm,t[x].lg);swap(t[x].rm,t[x].rg);
    t[x].lm*=-1;t[x].lg*=-1;t[x].rm*=-1;t[x].rg*=-1;
}
void puteql(int x,int w)
{
    if(!x)return;
    t[x].eql=t[x].v=w;t[x].sum=t[x].size*w;
    t[x].rev=t[x].inv=0;
    t[x].lm=t[x].rm=max(0,t[x].sum);
    t[x].lg=t[x].rg=min(0,t[x].sum);
}
void pushdown(int x)
{
    if(t[x].eql)puteql(ls,t[x].eql),puteql(rs,t[x].eql),t[x].eql=0;
    if(t[x].rev)putrev(ls),putrev(rs),t[x].rev^=1;
    if(t[x].inv)putinv(ls),putinv(rs),t[x].inv^=1;
}
void Splay(int x,int goal)
{
    while(t[x].ff!=goal)
    {
        int y=t[x].ff,z=t[y].ff;
        if(z!=goal)
            (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
        rotate(x);
    }
    if(!goal)rt=x;pushup(x);
}
int Kth(int x,int k)
{
    while(233)
    {
        pushdown(x);
        if(k<=t[ls].size)x=ls;
        else if(k==t[ls].size+1)return x;
        else k-=t[ls].size+1,x=rs;
    }
}
int split(int l,int r)
{
    int x=Kth(rt,l);Splay(x,0);
    int y=Kth(rt,r+2);Splay(y,x);
    return t[y].ch[0];
}
void Build(int l,int r,int ff)
{
    if(l>r)return;
    int mid=(l+r)>>1;
    t[mid].ff=ff;
    if(ff)t[ff].ch[ff<mid]=mid;
    else rt=mid;
    Build(l,mid-1,mid);Build(mid+1,r,mid);
    pushup(mid);
}
char S[MAX];
int n,m;
int main()
{
    n=read();m=read();
    scanf("%s",S+1);
    for(int i=1;i<=n;++i)t[i+1].v=(S[i]=='('?-1:1);
    Build(1,n+2,0);
    char ch[10];
    while(m--)
    {
        scanf("%s",ch);
        int l=read(),r=read(),x=split(l,r);
        if(ch[0]=='Q')printf("%d\n",(t[x].lm+1)/2+(1-t[x].rg)/2);
        else if(ch[0]=='S')putrev(x);
        else if(ch[0]=='R')
        {
            scanf("%s",ch);int w=(ch[0]=='('?-1:1);
            puteql(x,w);
        }
        else putinv(x);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值