bzoj2329: [HNOI2011]括号修复(fhq treap)

http://www.lydsy.com/JudgeOnline/problem.php?id=2329

 

需要改变的括号序列一定长这样 :)))(((

最少改变次数= 多余的‘)’/2 【上取整】 + 多余的‘(’ /2 【上取整】

把 ‘)’ 看做1,‘(’ 看做-1

那么最少改变次数=最大前缀和/2 【上取整】+ 最小后缀和/2 【上取整】

 

覆盖标记的优先级高于翻转标记和取反标记

即下放覆盖标记时,同时清空翻转标记和取反标记

且先下放覆盖标记

 

翻转:

最大前缀和 和 最大后缀和 交换

最小前缀和 和 最小后缀和 交换

 

取反:

最大前缀和 和 最小前缀和 交换,同时取反

最大后缀和 和 最小后缀和 交换,同时取反

 

最大XX和的下界为0,最小XX和的上界为0

因为最大XX和实际是多余的‘)’数量

最小XX和的相反数实际是多余的‘(’数量

数量不能为负数

 

注意点:

1、增加了首尾两个虚拟节点后,数组要多开2

2、平衡树每个节点由三部分组成,左子树、自己、右子树,打取反标记的时候不要忘记给自己取反

 

#include<cstdio>
#include<cstdlib>
#include<iostream>
 
using namespace std;
 
#define N 100003
 
char ss[N];
int a[N];
 
int root,tot;
 
int st[N];
 
bool rev[N],inv[N];
int tag[N];
int pre[N],suf[N];
int sum[N];
int pri[N],val[N];
 
int siz[N],ch[N][2];
 
int tmp;
 
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
 
inline int &max(int &a,int &b) { return a>b ? a : b; }
inline int &min(int &a,int &b) { return a<b ? a : b; }
 
void update(int x)
{
    int l=ch[x][0],r=ch[x][1];
    siz[x]=siz[l]+siz[r]+1;
    sum[x]=sum[l]+sum[r]+val[x];
    pre[x]=max(pre[l],sum[l]+pre[r]+val[x]);
    pre[x]=max(pre[x],sum[l]+val[x]);
    suf[x]=max(suf[r],sum[r]+suf[l]+val[x]);
    suf[x]=max(suf[x],sum[r]+val[x]);
}
 
int newnode(int v)
{
    val[++tot]=sum[tot]=v;
    pre[tot]=suf[tot]=max(0,val[tot]);
    sum[tot]=val[tot];
    siz[tot]=1;
    pri[tot]=rand();
    return tot;
}
 
int build(int l,int r)
{
    int top=0; int last,now;
    for(int i=l;i<=r;++i)
    {
        now=newnode(a[i]);
        last=0;
        while(top && pri[now]<pri[st[top]])
        {
            update(st[top]);
            last=st[top--];
        }
        if(top) ch[st[top]][1]=now;
        ch[now][0]=last; 
        st[++top]=now;
    }
    while(top) update(st[top--]);
    return st[1];
}
 
void down(int x)
{
    int l=ch[x][0],r=ch[x][1];
    if(tag[x])
    {
        if(l)
        {
            val[l]=tag[x];
            sum[l]=tag[x]*siz[l];
            pre[l]=suf[l]=max(0,sum[l]);
            rev[l]=inv[l]=false;
            tag[l]=tag[x];
        }
        if(r)
        {
            val[r]=tag[x];
            sum[r]=tag[x]*siz[r];
            pre[r]=suf[r]=max(0,sum[r]);
            rev[r]=inv[r]=false;
            tag[r]=tag[x];
        }
        tag[x]=0;
    }
    if(rev[x])
    {
        if(l)
        {   
            swap(pre[l],suf[l]);
            swap(ch[l][0],ch[l][1]);
            rev[l]^=1;
        }
        if(r)
        {   
            swap(pre[r],suf[r]);
            swap(ch[r][0],ch[r][1]);
            rev[r]^=1;
        }
        rev[x]^=1;
    }
    if(inv[x])
    {
        if(l)
        {
            tmp=pre[l];
            pre[l]=max(0,-(sum[l]-suf[l]));
            suf[l]=max(0,-(sum[l]-tmp));
            sum[l]=pre[l]+min(0,-sum[l]-pre[l]);
            val[l]=-val[l];
            inv[l]^=1;
        }
        if(r)
        {
            tmp=pre[r];
            pre[r]=max(0,-(sum[r]-suf[r]));
            suf[r]=max(0,-(sum[r]-tmp));
            sum[r]=pre[r]+min(0,-sum[r]-pre[r]);
            val[r]=-val[r];
            inv[r]^=1;
        }
        inv[x]^=1;
    }
}
 
void split(int now,int k,int &x,int &y)
{
    if(!now) x=y=0;
    else
    {
        down(now);
        if(k<=siz[ch[now][0]])
        {
            y=now;
            split(ch[now][0],k,x,ch[now][0]);
        }
        else
        {
            x=now;
            split(ch[now][1],k-siz[ch[now][0]]-1,ch[now][1],y);
        }
        update(now);
    }       
}
 
int merge(int x,int y)
{
    if(x) down(x);
    if(y) down(y);
    if(!x || !y) return x+y;
    if(pri[x]<pri[y])
    {
        ch[x][1]=merge(ch[x][1],y);
        update(x);
        return x;
    }
    else
    {
        ch[y][0]=merge(x,ch[y][0]);
        update(y);
        return y;
    }
}
     
 
int main()
{
    int n,m;
    read(n); read(m);
    scanf("%s",ss+2);
    for(int i=2;i<=n+1;++i) 
        if(ss[i]==')') a[i]=1;
        else a[i]=-1;
    root=build(1,n+2);
    int l,r; char s[10],cc[3];
    int a,b,c,d,e;
    while(m--)
    {
        scanf("%s",s);
        read(l); read(r);
        l++; r++;
        split(root,r,a,b);
        split(a,l-1,c,d);
        if(s[0]=='R')
        {
            scanf("%s",cc);
            e= cc[0]==')' ? 1 : -1;
            tag[d]=e;
            val[d]=e;
            sum[d]=e*siz[d];
            pre[d]=suf[d]=max(0,sum[d]);
            rev[d]=inv[d]=false;
        }
        else if(s[0]=='S')
        {
            rev[d]=true;
            swap(ch[d][0],ch[d][1]);
            swap(pre[d],suf[d]);
        }
        else if(s[0]=='I')
        {
            inv[d]=true;
            tmp=pre[d];
            pre[d]=max(0,-(sum[d]-suf[d]));
            suf[d]=max(0,-(sum[d]-tmp));
            sum[d]=pre[d]+min(0,-sum[d]-pre[d]);
            val[d]=-val[d];
        }
        else printf("%d\n",(pre[d]+1)/2+(-sum[d]+pre[d]+1)/2);
        root=merge(merge(c,d),b);
    }
}

 

2329: [HNOI2011]括号修复

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1229  Solved: 580
[Submit][Status][Discuss]

Description

posted @ 2018-02-01 21:27  TRTTG  阅读(206)  评论(0编辑  收藏  举报