BZOJ2329 HNOI2011括号修复

Problem

BZOJ

Solution

考虑询问,如果我们把相互匹配的括号删除,那么我们最终会得到形如)))(的序列。
对于这样一个序列,我们不妨贪心。将左边连续的l个右括号,从第一个到(l+1)/2分别改为左括号。对右边则反之。
那么当l为偶数时,左边会变得合法。当l为奇数时,会多余一个左括号,但由于题目保证了有解,即l+r为偶数,这个多余的左括号将与右边的多余右括号匹配。
这样显然是没有冗余操作的。

这里用了一个小trick,可以只需要维护左右最大子段和即可。
注意replace操作可以覆盖swap和invert操作,因为会使得这两个操作没有意义。

用了无旋treap实现,代码写起来还是短一些。

Code

#include 
#include 
#include 
using namespace std;
const int maxn=100010;
int n,m,sz,rt,a,b,c,ans,val[maxn],rnd[maxn],s[maxn],ch[maxn][2],f[maxn];
int l[maxn],r[maxn],sum[maxn],lazy[maxn],rev[maxn],inv[maxn];
char op[10],ss[maxn];
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return xint new_node(char k)//-1->( 1->)
{
    s[++sz]=1;rnd[sz]=rand();
    if(k=='(') val[sz]=-1;
    else val[sz]=1;
    return sz;
}
void pushup(int x)
{
    s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
    sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];
    l[x]=max(l[ch[x][0]],sum[ch[x][0]]+l[ch[x][1]]+val[x]);
    l[x]=max(l[x],sum[ch[x][0]]+val[x]);
    r[x]=max(r[ch[x][1]],sum[ch[x][1]]+r[ch[x][0]]+val[x]);
    r[x]=max(r[x],sum[ch[x][1]]+val[x]);
}
void pushdown(int x)
{
    int L=ch[x][0],R=ch[x][1];
    if(lazy[x])
    {
        if(L)
        {
            sum[L]=s[L]*lazy[x];lazy[L]=val[L]=lazy[x];
            l[L]=r[L]=max(0,sum[L]);inv[L]=rev[L]=0;
        }
        if(R)
        {
            sum[R]=s[R]*lazy[x];lazy[R]=val[R]=lazy[x];
            l[R]=r[R]=max(0,sum[R]);inv[R]=rev[R]=0;
        }
        lazy[x]=0;
    }
    if(inv[x])
    {
        if(L)
        {
            int tmp=l[L];
            val[L]=-val[L];inv[L]^=1;
            l[L]=max(0,-(sum[L]-r[L]));r[L]=max(0,-(sum[L]-tmp));
            sum[L]=l[L]+min(0,-sum[L]-l[L]);
        }
        if(R)
        {
            int tmp=l[R];
            val[R]=-val[R];inv[R]^=1;
            l[R]=max(0,-(sum[R]-r[R]));r[R]=max(0,-(sum[R]-tmp));
            sum[R]=l[R]+min(0,-sum[R]-l[R]);
        }
        inv[x]=0;
    }
    if(rev[x])
    {
        if(L) rev[L]^=1,swap(l[L],r[L]),swap(ch[L][0],ch[L][1]);
        if(R) rev[R]^=1,swap(l[R],r[R]),swap(ch[R][0],ch[R][1]);
        rev[x]=0;
    }
}
int merge(int x,int y)
{
    if(!x||!y){pushup(x+y);return x+y;}
    if(lazy[x]||inv[x]||rev[x]) pushdown(x);
    if(lazy[y]||inv[y]||rev[y]) pushdown(y);
    if(rnd[x]1]=merge(ch[x][1],y);pushup(x);
        return x;
    }
    else
    {
        ch[y][0]=merge(x,ch[y][0]);pushup(y);
        return y;
    }
}
void split(int now,int k,int &x,int &y)
{
    if(!now){x=y=0;return ;}
    if(lazy[now]||inv[now]||rev[now]) pushdown(now);
    if(k<=s[ch[now][0]]) y=now,split(ch[now][0],k,x,ch[now][0]);
    else x=now,split(ch[now][1],k-s[ch[now][0]]-1,ch[now][1],y);
    pushup(now);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int L,R,tmp;
    srand(19260817);
    scanf("%d%d%s",&n,&m,ss+1);
    for(int i=1;i<=n;i++) rt=merge(rt,new_node(ss[i]));
    while(m--)
    {
        scanf("%s%d%d",op,&L,&R);
        split(rt,R,a,c);split(a,L-1,a,b);
        if(op[0]=='R')
        {
            scanf("%s",op);
            if(op[0]=='(') val[b]=lazy[b]=-1;
            else val[b]=lazy[b]=1;
            sum[b]=s[b]*lazy[b];l[b]=r[b]=max(0,sum[b]);
            rev[b]=inv[b]=0;
        }
        else if(op[0]=='S') rev[b]^=1,swap(l[b],r[b]),swap(ch[b][0],ch[b][1]);
        else if(op[0]=='I')
        {
            val[b]=-val[b];inv[b]^=1;
            tmp=l[b];l[b]=max(0,-(sum[b]-r[b]));r[b]=max(0,-(sum[b]-tmp));
            sum[b]=l[b]+min(0,-sum[b]-l[b]);
        }
        else if(op[0]=='Q')
        {
            ans=(l[b]+1>>1)+(l[b]-sum[b]+1>>1);
            printf("%d\n",ans);
        }
        rt=merge(merge(a,b),c);
    }
    return 0;
}

你可能感兴趣的:(无旋treap,好题集,平衡树,HNOI,BZOJ)