bzoj 2209: [Jsoi2011]括号序列 splay

2209: [Jsoi2011]括号序列

Time Limit: 20 Sec  Memory Limit: 259 MB
Submit: 833  Solved: 392
[Submit][Status]

Description

Input

输入数据的第一行包含两个整数N和Q,分别表示括号序列的长度,以及操作的个数。 第二行包含一个长度为N的括号序列。 接下来Q行,每行三个整数t、x和y,分别表示操作的类型、操作的开始位置和操作的结 束位置,输入数据保证x不小于y。其中t=0表示询问操作、t=1表示反转操作、t=2表示翻转操 作。

Output

对于每一个询问操作,输出一行,表示将括号序列的该子序列修改为配对,所需的最少改动 个数。

Sample Input

6 3
)(())(
0 1 6
0 1 4
0 3 4

Sample Output

2
2
0

HINT

100%的数据满足N,Q不超过10^5

  终于算是会写splay了,这道题涉及到splay的区间翻转,取反,询问以及lazy标记下放等操作,算是涵盖了splay的基本用法。

  合法的括号序列的一个性质是,以正括号为1,反括号为-1,合法序列和为0,且所有前缀权值和非负。顾可以通过类似于线段树求区间最大子段和方式维护,由于涉及到区间翻转,故改为splay维护。

  这次编写问题还是在标记同步上,具体来说,在get_kth()调用前一定要down(),修改子树后要讲修改后的值传回根节点。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 210000
#define MAXT 210000
inline int min(int x,int y,int z)
{
        return min(x,min(y,z));
}
inline int min(int a,int b,int c,int d)
{
        return min(min(a,b),min(c,d));
}
inline int max(int x,int y,int z)
{
        return max(x,max(y,z));
}
inline int max(int a,int b,int c,int d)
{
        return max(max(a,b),max(c,d));
}
int num[MAXN];
struct splay_tree
{
        int ch[MAXT][2],pnt[MAXT];
        int val[MAXT],siz[MAXT],sum[MAXT],lx[MAXT][2],rx[MAXT][2];
        bool rev[MAXT],neg[MAXT];
        int stack[MAXT],tops;
        int topt;
        int root;
        splay_tree()
        {
                topt=0,root=0;
                tops=-1;
        }
        void reverse(int now)
        {
                if (!now)return;
                swap(lx[now][0],rx[now][0]);
                swap(lx[now][1],rx[now][1]);
                swap(ch[now][0],ch[now][1]);
                rev[now]^=1;
        }
        void negate(int now)
        {
                if (!now)return ;
                val[now]=-val[now];
                sum[now]=-sum[now];
                swap(lx[now][0],lx[now][1]);
                swap(rx[now][0],rx[now][1]);
                lx[now][0]=-lx[now][0];
                rx[now][0]=-rx[now][0];
                lx[now][1]=-lx[now][1];
                rx[now][1]=-rx[now][1];
                neg[now]^=1;
        }
        void update(int now)
        {
                lx[now][0]=min(lx[ch[now][0]][0],sum[ch[now][0]],sum[ch[now][0]]+val[now],sum[ch[now][0]]+val[now]+lx[ch[now][1]][0]);
                lx[now][1]=max(lx[ch[now][0]][1],sum[ch[now][0]],sum[ch[now][0]]+val[now],sum[ch[now][0]]+val[now]+lx[ch[now][1]][1]);
                rx[now][0]=min(rx[ch[now][1]][0],sum[ch[now][1]],sum[ch[now][1]]+val[now],sum[ch[now][1]]+val[now]+rx[ch[now][0]][0]);
                rx[now][1]=max(rx[ch[now][1]][1],sum[ch[now][1]],sum[ch[now][1]]+val[now],sum[ch[now][1]]+val[now]+rx[ch[now][0]][1]);
                sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+val[now];
                siz[now]=siz[ch[now][0]]+siz[ch[now][1]]+1;
        }
        void down(int now)
        {
                if (rev[now])
                {
                        reverse(ch[now][0]);
                        reverse(ch[now][1]);
                        rev[now]=0;
                }
                if (neg[now])
                {
                        negate(ch[now][0]);
                        negate(ch[now][1]);
                        neg[now]=0;
                }
        }
        void rotate(int now)
        {
                int p=pnt[now],anc=pnt[p];
                int dir=ch[p][0]==now;
                if (anc)
                        ch[anc][ch[anc][1]==p]=now;
                pnt[now]=anc;
                pnt[ch[now][dir]]=p;
                ch[p][1-dir]=ch[now][dir];
                pnt[p]=now;
                ch[now][dir]=p;
                update(p);
                update(now);
        }
        void splay(int now,int tp=0)
        {
                int x=now;
                tops=-1;
                while (x!=tp)
                {
                        stack[++tops]=x;
                        x=pnt[x];
                }
                while (~tops)
                {
                        down(stack[tops--]);
                }
                while (now!=tp && pnt[now]!=tp)
                {
                        int p=pnt[now],anc=pnt[p];
                        if (anc==tp)
                                rotate(now);
                        else if ((ch[p][0]==now) == (ch[anc][0]==p))
                                rotate(p),rotate(now);
                        else
                                rotate(now),rotate(now);
                }
                if (tp==0)
                        root=now;
        }
        int get_kth(int now,int rk)
        {
                if (!now)throw 1;
                down(now);
                if (siz[ch[now][0]]+1==rk)
                        return now;
                if (siz[ch[now][0]]+1<rk)
                        return get_kth(ch[now][1],rk-siz[ch[now][0]]-1);
                else
                        return get_kth(ch[now][0],rk);
        }
        void insert(int pos,int v)
        {
                if (!root)
                {
                        root=++topt;
                        pnt[topt]=0;
                        val[topt]=v;
                        update(topt);
                }else if (!pos)
                {
                        splay(get_kth(root,pos));
                        ch[root][0]=topt;
                        pnt[topt]=root;
                        val[topt]=v;
                        update(topt);
                        update(root);
                }else
                {
                        splay(get_kth(root,pos));
                        val[++topt]=v;
                        pnt[topt]=root;
                        ch[topt][1]=ch[root][1];
                        pnt[ch[root][1]]=topt;
                        ch[root][1]=topt;
                        update(topt);
                        update(root);
                }
        }
        int get_result(int now)
        {
                int res=0,t;
                t=-lx[now][0];
                res=t/2+t%2;
                t=res*2+sum[now];
                res+=abs(t)/2;
                return res;
        }
        int query(int l,int r)
        {
                if (l==1 && r==siz[root])
                        return get_result(root);
                if (l==1)
                {
                        splay(get_kth(root,r+1));
                        return get_result(ch[root][0]);
                }
                if (r==siz[root])
                {
                        splay(get_kth(root,l-1));
                        return get_result(ch[root][1]);
                }
                splay(get_kth(root,r+1));
                splay(get_kth(root,l-1),root);
                return get_result(ch[ch[root][0]][1]);
        }
        void make_reverse(int l,int r)
        {
                if (l==1 && r==siz[root])
                        return reverse(root);
                if (l==1)
                {
                        splay(get_kth(root,r+1));
                        reverse(ch[root][0]);
                        update(root);
                        return ;
                }
                if (r==siz[root])
                {
                        splay(get_kth(root,l-1));
                        reverse(ch[root][1]);
                        update(root);
                        return ;
                }
                splay(get_kth(root,r+1));
                splay(get_kth(root,l-1),root);
                reverse(ch[ch[root][0]][1]);
                update(ch[root][0]);
                update(root);
        }
        void make_negate(int l,int r)
        {
                if (l==1 && r==siz[root])
                        return negate(root);
                if (l==1)
                {
                        splay(get_kth(root,r+1));
                        negate(ch[root][0]);
                        update(root);
                        return ;
                }
                if (r==siz[root])
                {
                        splay(get_kth(root,l-1));
                        negate(ch[root][1]);
                        update(root);
                        return ;
                }
                splay(get_kth(root,r+1));
                splay(get_kth(root,l-1),root);
                negate(ch[ch[root][0]][1]);
                update(ch[root][0]);
                update(root);

        }
        void scan(int now)
        {
                if (!now)return ;
                if (pnt[ch[now][0]]!=now && ch[now][0])throw 1;
                if (pnt[ch[now][1]]!=now && ch[now][1])throw 2;
                if (siz[now]!=siz[ch[now][0]]+siz[ch[now][1]]+1)throw 3;
                scan(ch[now][0]);
                printf("%d ",val[now]);
                scan(ch[now][1]);
        }
}pp;
int main()
{
        //freopen("input.txt","r",stdin);
        //    freopen("output.txt","w",stdout);
        int n,m,i,j,k,x,y,z;
        scanf("%d%d\n",&n,&m);
        char ch;
        for (i=1;i<=n;i++)
        {
                scanf("%c",&ch);
                if (ch==')')
                        pp.insert(i-1,-1);
                else
                        pp.insert(i-1,1);
        }
        int opt;
        for (i=1;i<=m;i++)
        {
                scanf("%d%d%d",&opt,&x,&y);
            //    pp.scan(pp.root);printf("\n");
                if (opt==0)
                {
                        printf("%d\n",pp.query(x,y));
                }else if (opt==1)
                {
                        pp.make_negate(x,y);
                }else if (opt==2)
                {
                        pp.make_reverse(x,y);
                }
        }
}

 

转载于:https://www.cnblogs.com/mhy12345/p/4106690.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值