• [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!

  • 相关阅读:
    iOS----------弹窗动画
    书单
    如何屏蔽垃圾短信
    2018年IOS/Android UI设计规范
    关于Keychain
    OpenUDID 和 IDFA 比较
    iOS-----------关于UDID
    iOS-----------设置自定义字体
    【2020Python修炼记】前端开发之 JavaScript 基础
    【2020Python修炼记】前端开发之 CSS基础布局
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10146970.html
Copyright © 2020-2023  润新知