bzoj 2329 [HNOI2011]括号修复 splay

区间赋值,区间翻转,区间反转,也就splay能干这些事吧。。。
维护一个区间最小值low,区间最大值up,区间和sum,然后一段区间的答案是
(low[x]+1)/2+(sum[x]+(low[x]+1)/22)/2

再打一坨标记就行了,注意标记重叠

#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define which(x) (ch[fa[x]][1]==x)
int n,m,root,cnt;
char s[N];
int val[N],size[N],rev[N],inv[N],rep[N];
int ch[N][2],fa[N],up[N],low[N],sum[N];
void pushup(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];
    up[x]=max(up[ch[x][0]],up[ch[x][1]]+sum[ch[x][0]]+val[x]);
    low[x]=min(low[ch[x][0]],low[ch[x][1]]+sum[ch[x][0]]+val[x]);
}
void invert(int x)
{
    val[x]=-val[x],inv[x]^=1;
    sum[x]=-sum[x];
    swap(low[x],up[x]);
    up[x]=-up[x];low[x]=-low[x];    
}
void replace(int x,int v)
{
    inv[x]=0;
    if(v==1)
    {
        rep[x]=val[x]=1;sum[x]=size[x];
        up[x]=size[x];low[x]=0;
    }
    else 
    {
        rep[x]=val[x]=-1;sum[x]=-size[x];
        up[x]=0;low[x]=-size[x];
    }
}
void reverse(int x)
{
    rev[x]^=1;
    swap(low[x],up[x]);
    up[x]=sum[x]-up[x];
    low[x]=sum[x]-low[x];
}
void pushdown(int x)
{
    if(rev[x])
    {
        swap(ch[x][0],ch[x][1]);
        reverse(ch[x][0]);reverse(ch[x][1]);
        rev[x]=0;
    }
    if(rep[x])
    {
        replace(ch[x][0],rep[x]);
        replace(ch[x][1],rep[x]);
        rep[x]=0;
    }
    if(inv[x])
    {
        invert(ch[x][0]);invert(ch[x][1]);
        inv[x]=0;
    }
}
void down(int x)
{
    if(fa[x])down(fa[x]);
    pushdown(x);
}
int build(int l,int r)
{
    if(l>r)return 0;
    int mid=(l+r)>>1,ret=++cnt;
    val[ret]=(s[mid]=='(' ? 1:-1);
    ch[ret][0]=build(l,mid-1);
    ch[ret][1]=build(mid+1,r);
    fa[ch[ret][0]]=fa[ch[ret][1]]=ret;
    pushup(ret);
    return ret;
}
int find(int x,int K)
{
    pushdown(x);
    if(K==size[ch[x][0]]+1)return x;
    if(K<=size[ch[x][0]])
        return find(ch[x][0],K);
    return find(ch[x][1],K-size[ch[x][0]]-1);
}
void rotate(int x)
{
    int y=fa[x],k=which(x);
    ch[y][k]=ch[x][k^1];
    ch[x][k^1]=y;
    ch[fa[y]][which(y)]=x;

    fa[x]=fa[y];fa[y]=x;
    fa[ch[y][k]]=y;
    pushup(y);pushup(x);
}
void splay(int x,int tar)
{
    down(x);
    while(fa[x]!=tar)
    {
        int y=fa[x];
        if(fa[y]==tar)rotate(x);
        else 
        {
            if(which(x)^which(y))rotate(x);
            else rotate(y);
            rotate(x);
        }
    }
    if(!tar)root=x;
}
int main()
{
    scanf("%d%d%s",&n,&m,s+1);
    root=build(0,n+1);
    for(int l,r;m--;)
    {
        scanf("%s%d%d",s+1,&l,&r);
        int pl=find(root,l),pr=find(root,r+2);
        splay(pl,0);splay(pr,root);
        int x=ch[pr][0];
        if(s[1]=='R')
        {
            scanf("%s",s+1);
            replace(x,s[1]=='(' ? 1:-1);
        }
        else if(s[1]=='S')reverse(x);
        else if(s[1]=='I')invert(x);
        else 
        {
            int t=(-low[x]+1)/2;
            printf("%d\n",t+(sum[x]+t*2)/2);
        }
        pushup(pr);pushup(pl);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值