zoukankan      html  css  js  c++  java
  • [HNOI2011]括号修复 / [JSOI2011]括号序列

    传送门

    Solution

    一道题花费了两天的时间……

    在大佬@PinkRabbit的帮助下,终于AC了,感动……

    首先,我们考虑一个括号序列被修改成合法序列需要的次数:

    • 我们需要修改的其实是形如...)))))(((((...
    • 我们把(看成是-1,把)看成是1,那么其实只要知道了区间的前缀最大值pr和后缀最小值sum-pr

    那么就有$$ans=left lceil frac{pr}{2} ight ceil+left lceil frac{-sum+su}{2} ight ceil$$

    如果我们维护了区间的前缀最大值pr和后缀最大值su和区间和sum

    • 区间翻转:swap(pr,su)
    • 区间反转:pr=-(sum-su)同时su=-(sum-pr),这里的(sum-su)就是前缀最小值,因为区间取了反,所以就是前缀最大值啦
    • 区间覆盖:直接打标记

    所有区间操作都可以用平衡树来实现

    要注意:区间覆盖的优先级应大于另外两个操作


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
        int 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<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    #define MN 100005
    char s[MN];
    class fhq
    {
        private:
            int sz;
            int pri[MN],ls[MN],rs[MN],siz[MN];
            int pr[MN],su[MN],tt[MN],cover[MN],V[MN];
            bool rev[MN],inv[MN];
            inline unsigned int random()
            {
                static unsigned int x=23333;
                return x^=x<<13,x^=x>>17,x^=x<<5;
            }
            inline void up(int x)
            {
                siz[x]=1+siz[ls[x]]+siz[rs[x]];
                tt[x]=tt[ls[x]]+tt[rs[x]]+V[x];
                pr[x]=max(pr[ls[x]],tt[ls[x]]+V[x]+pr[rs[x]]);
                su[x]=max(su[rs[x]],tt[rs[x]]+V[x]+su[ls[x]]);
            }
            inline void update(int x,int opt)
            {
                if(!x) return; 
                if(opt==1)
                {
                    std::swap(pr[x],su[x]);std::swap(ls[x],rs[x]);
                    rev[ls[x]]^=1;rev[rs[x]]^=1;
                }
                if(opt==2)
                {
                    V[x]=-V[x];
                    pr[x]=-(tt[x]-pr[x]);su[x]=-(tt[x]-su[x]);
                    std::swap(pr[x],su[x]);
                    tt[x]=-tt[x];
                    inv[ls[x]]^=1;inv[rs[x]]^=1;
                }
                if(opt==3)
                {
                    V[x]=cover[x];tt[x]=cover[x]*siz[x];
                    su[x]=max(0,tt[x]);pr[x]=max(0,tt[x]);
                    cover[ls[x]]=cover[rs[x]]=cover[x];
                    rev[ls[x]]=inv[ls[x]]=0;
                    rev[rs[x]]=inv[rs[x]]=0;
                }
            }
            inline void down(int x)
            {
                if(cover[x]) update(ls[x],3),update(rs[x],3),cover[x]=0;
                if(rev[x]) update(ls[x],1),update(rs[x],1),rev[x]=0;
                if(inv[x]) update(ls[x],2),update(rs[x],2),inv[x]=0;
            }
        public:
            int rt;
            int Merge(int rt1,int rt2)
            {
                if(!rt1||!rt2) return rt2|rt1;
                if(pri[rt1]<pri[rt2])
                {
                    down(rt1),rs[rt1]=Merge(rs[rt1],rt2);
                    up(rt1);return rt1;
                }
                else
                {
                    down(rt2),ls[rt2]=Merge(rt1,ls[rt2]);
                    up(rt2);return rt2;
                }
            }
            void Split(int x,int k,int&rt1,int&rt2)
            {
                if(!x) return (void)(rt1=rt2=0);
                down(x);
                if(k<=siz[ls[x]])
                {
                    Split(ls[x],k,rt1,rt2);
                    ls[x]=rt2;up(x);rt2=x;
                }
                else
                {
                    Split(rs[x],k-siz[ls[x]]-1,rt1,rt2);
                    rs[x]=rt1;up(x);rt1=x;
                }
            }
            void Build(int &x,int l,int r)
            {
                if(l>r) return;int mid=l+r>>1;
                x=++sz;
                V[x]=tt[x]=(s[mid]==')'?1:-1),pri[x]=random();
                if(l==r) return(void)(pr[x]=su[x]=max(0,V[x]),siz[x]=1);
                Build(ls[x],l,mid-1),Build(rs[x],mid+1,r);up(x);
            }
            void Reverse(int l,int r)
            {
                register int rt1,rt2,rt3,rt4;
                Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
                rev[rt3]^=1;update(rt3,1);rt=Merge(rt1,Merge(rt3,rt4));
            }
            void Invert(int l,int r)
            {
                register int rt1,rt2,rt3,rt4;
                Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
                inv[rt3]^=1;update(rt3,2);rt=Merge(rt1,Merge(rt3,rt4));
            }
            void Replace(int l,int r,int c)
            {
                register int rt1,rt2,rt3,rt4;
                Split(rt,l-1,rt1,rt2);Split(rt2,r-l+1,rt3,rt4);
                cover[rt3]=c,update(rt3,3);rev[rt3]=inv[rt3]=0;rt=Merge(rt1,Merge(rt3,rt4));
            }
            int Query(int l,int r)
            {
                register int rt1,rt2,rt3,rt4,ret;
                Split(rt,l-1,rt1,rt2);
                Split(rt2,r-l+1,rt3,rt4);
                ret=(pr[rt3]+1)/2+(-tt[rt3]+pr[rt3]+1)/2;
                rt=Merge(rt1,Merge(rt3,rt4));
                return ret;
            }
    }T;
    int main(){
        register int n,m,l,r;
        n=read(),m=read();
        scanf("%s",s+1);T.Build(T.rt,1,n);
        register char opt[10],c[2];
        while(m--)
        {
            scanf("%s",opt+1);l=read(),r=read();
            if(opt[1]=='R') scanf("%s",c),T.Replace(l,r,c[0]=='('?-1:1);
            if(opt[1]=='S') T.Reverse(l,r);
            if(opt[1]=='I') T.Invert(l,r);
            if(opt[1]=='Q') printf("%d
    ",T.Query(l,r));
        }
        return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10146970.html
Copyright © 2011-2022 走看看