• [BZOJ2329][HNOI2011]括号修复


    bzoj
    luogu

    题意

    你需要维护一个括号序列,支持如下四种操作:
    1、把区间([l,r])全部改成(或是)
    2、把区间([l,r])翻转。
    3、把区间([l.r])反转,即())(
    4、查询区间([l,r])至少要修改几个括号才能全部匹配。

    sol

    一个区间的括号去掉匹配后一定长成)))))((((((这个样子。
    所以答案就是未匹配左括号个数/2+未匹配右括号个数/2,除法向上取整。
    考虑把左括号看成1,右括号看成-1。这样左边的未匹配右括号个数就是最小前缀和的绝对值,右边的就是最大后缀和。
    要维护区间翻转反转就还得同时维护最大前缀和与最小后缀和。
    注意这里最小XX数的上界是(0),最大XX数的下界也是(0)
    (splay)维护即可。

    区间覆盖的优先级高于翻转反转,所以区间覆盖后要把翻转反转的标记都清掉。翻转反转的优先级相同,先翻转再反转和先反转再翻转是一样的。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e5+5;
    int n,m,val[N],fa[N],ch[2][N],lmi[N],rmi[N],lmx[N],rmx[N],sum[N],sz[N],root;
    int tag[N],inv[N],rev[N];
    char s[N];
    void pushup(int x)
    {
    	sum[x]=sum[ch[0][x]]+val[x]+sum[ch[1][x]];
    	sz[x]=sz[ch[0][x]]+sz[ch[1][x]]+1;
    	lmi[x]=min(lmi[ch[0][x]],sum[ch[0][x]]+val[x]+lmi[ch[1][x]]);
    	rmi[x]=min(rmi[ch[1][x]],sum[ch[1][x]]+val[x]+rmi[ch[0][x]]);
    	lmx[x]=max(lmx[ch[0][x]],sum[ch[0][x]]+val[x]+lmx[ch[1][x]]);
    	rmx[x]=max(rmx[ch[1][x]],sum[ch[1][x]]+val[x]+rmx[ch[0][x]]);
    }
    void cover(int x,int v)
    {
    	if (!x) return;
    	sum[x]=sz[x]*v;
    	lmi[x]=rmi[x]=min(0,sum[x]);
    	lmx[x]=rmx[x]=max(0,sum[x]);
    	val[x]=tag[x]=v;inv[x]=rev[x]=0;
    }
    void reverse(int x)
    {
    	if (!x) return;
    	swap(ch[0][x],ch[1][x]);
    	swap(lmi[x],rmi[x]);swap(lmx[x],rmx[x]);
    	rev[x]^=1;
    }
    void inverse(int x)
    {
    	if (!x) return;
    	swap(lmi[x],lmx[x]);lmi[x]*=-1;lmx[x]*=-1;
    	swap(rmi[x],rmx[x]);rmi[x]*=-1;rmx[x]*=-1;
    	val[x]*=-1;sum[x]*=-1;inv[x]^=1;
    }
    void pushdown(int x)
    {
    	if (tag[x]) cover(ch[0][x],tag[x]),cover(ch[1][x],tag[x]),tag[x]=0;
    	if (rev[x]) reverse(ch[0][x]),reverse(ch[1][x]),rev[x]=0;
    	if (inv[x]) inverse(ch[0][x]),inverse(ch[1][x]),inv[x]=0;
    }
    int build(int l,int r,int ff)
    {
    	if (l>r) return 0;
    	int mid=l+r>>1;
    	fa[mid]=ff;
    	ch[0][mid]=build(l,mid-1,mid);
    	ch[1][mid]=build(mid+1,r,mid);
    	pushup(mid);return mid;
    }
    bool son(int x){return x==ch[1][fa[x]];}
    void rotate(int x)
    {
    	int y=fa[x],z=fa[y],c=son(x);
    	ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
    	fa[x]=z;if (z) ch[son(y)][z]=x;
    	ch[c^1][x]=y;fa[y]=x;pushup(y);
    }
    void splay(int x,int goal)
    {
    	for (int y=fa[x];y!=goal;rotate(x),y=fa[x])
    		if (fa[y]!=goal) son(x)^son(y)?rotate(x):rotate(y);
    	pushup(x);if (!goal) root=x;
    }
    void Kth(int k,int goal)
    {
    	int x=root;
    	while (233)
    	{
    		pushdown(x);
    		if (k<=sz[ch[0][x]]) x=ch[0][x];
    		else if (k==sz[ch[0][x]]+1) {splay(x,goal);return;}
    		else k-=sz[ch[0][x]]+1,x=ch[1][x];
    	}
    }
    int main()
    {
    	n=gi();m=gi();scanf("%s",s+2);
    	for (int i=2;i<=n+1;++i) val[i]=s[i]=='('?1:-1;
    	root=build(1,n+2,0);
    	while (m--)
    	{
    		scanf("%s",s);int l=gi(),r=gi();char op;
    		Kth(l,0);Kth(r+2,root);int pos=ch[0][ch[1][root]];
    		if (s[0]=='R') op=getchar(),cover(pos,op=='('?1:-1);
    		if (s[0]=='S') reverse(pos);
    		if (s[0]=='I') inverse(pos);
    		if (s[0]=='Q') printf("%d
    ",(-lmi[pos]+1)/2+(rmx[pos]+1)/2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Proc、宿主变量、指示变量、数组变量、通信区sqlca,oraca ---(day07)
    Cursor、Exception、Procedure、Function、Package、Trigger(day06)
    大话设计模式C++版——建造者模式
    大话设计模式C++版——观察者模式
    大话设计模式C++版——代理模式
    大话设计模式C++版——工厂模式在COM中的典型应用
    大话设计模式C++版——抽象工厂模式
    大话设计模式C++版——工厂方法模式
    exe文件无法打开
    数据驱动编程之表驱动法
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8808910.html
Copyright © 2020-2023  润新知