●BZOJ 2329 [HNOI2011]括号修复.cpp

题链:

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

题解:

Splay

类似 BZOJ 2329 [HNOI2011]括号修复

只是多了一个Replace(替换)操作,

然后就要主要lazy标记之间的影响了。

1).Replace可以直接覆盖另外两个标记,

2).当已经有Replace标记,再覆盖Invert标记时,直接把Replace标记取反即可;在覆盖Swap标记时,Replace标记不变。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100500
using namespace std;
char s[10];
int N,M;
struct SPT{
	int pmx[MAXN],pmn[MAXN],smx[MAXN],smn[MAXN],sum[MAXN],key[MAXN];
	int ch[MAXN][2],siz[MAXN],fa[MAXN],cg[MAXN],lazy[MAXN],rt;
	void Invert(int x){
		sum[x]*=-1; key[x]*=-1;
		pmx[x]*=-1; pmn[x]*=-1; swap(pmx[x],pmn[x]);
		smx[x]*=-1; smn[x]*=-1; swap(smx[x],smn[x]);
	}
	void Swap(int x){
		swap(pmx[x],smx[x]);
		swap(pmn[x],smn[x]);
		swap(ch[x][0],ch[x][1]);
	}
	void Replace(int x,int c){
		key[x]=c; sum[x]=c*siz[x];
		pmx[x]=max(sum[x],0); pmn[x]=min(sum[x],0);
		smx[x]=max(sum[x],0); smn[x]=min(sum[x],0);
	}
	void Pushup(int x){
		siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
		sum[x]=sum[ch[x][0]]+key[x]+sum[ch[x][1]];
		pmx[x]=max(pmx[ch[x][0]],sum[ch[x][0]]+key[x]+pmx[ch[x][1]]);
		pmn[x]=min(pmn[ch[x][0]],sum[ch[x][0]]+key[x]+pmn[ch[x][1]]);
		smx[x]=max(smx[ch[x][1]],sum[ch[x][1]]+key[x]+smx[ch[x][0]]);
		smn[x]=min(smn[ch[x][1]],sum[ch[x][1]]+key[x]+smn[ch[x][0]]);
	}
	void Pushdown(int x){
		if(cg[x]!=0){
			Replace(ch[x][0],cg[x]); cg[ch[x][0]]=cg[x]; lazy[ch[x][0]]=0;
			Replace(ch[x][1],cg[x]); cg[ch[x][1]]=cg[x]; lazy[ch[x][1]]=0;
			cg[x]=0;
		}
		if(lazy[x]&1){
			Invert(ch[x][0]);
			if(!cg[ch[x][0]]) lazy[ch[x][0]]^=1; else cg[ch[x][0]]*=-1;
			Invert(ch[x][1]);
			if(!cg[ch[x][1]]) lazy[ch[x][1]]^=1; else cg[ch[x][1]]*=-1;
			lazy[x]^=1;
		}
		if(lazy[x]&2){
			Swap(ch[x][0]);
			if(!cg[ch[x][0]]) lazy[ch[x][0]]^=2;
			Swap(ch[x][1]);
			if(!cg[ch[x][1]]) lazy[ch[x][1]]^=2;
			lazy[x]^=2;
		}
	}
	void Rotate(int x,int &k){
		static int y,z,l,r;
		y=fa[x]; z=fa[y];
		l=ch[y][0]!=x; r=l^1;
		if(!z) k=x;
		else ch[z][ch[z][0]!=y]=x;
		fa[ch[x][r]]=y; fa[y]=x; fa[x]=z;
		ch[y][l]=ch[x][r]; ch[x][r]=y;
		Pushup(y);
	}
	void Splay(int x,int &k){
		static int y,z;
		while(x!=k){
			y=fa[x]; z=fa[y];
			if(y!=k) (ch[z][0]!=y)^(ch[y][0]!=x)?
				Rotate(x,k):Rotate(y,k);
			Rotate(x,k);
		}
		Pushup(x);
	}
	int find(int x,int num){
		Pushdown(x);
		if(num<=siz[ch[x][0]]) return find(ch[x][0],num);
		else if(num==siz[ch[x][0]]+1) return x;
		else return find(ch[x][1],num-siz[ch[x][0]]-1);
	}
	int Split(int l,int r){
		static int dl,dr;
		dl=find(rt,l); dr=find(rt,r+2);
		Splay(dl,rt); Splay(dr,ch[dl][1]);
		return ch[dr][0];
	}
	void Modify(int l,int r,int type){
		static int p;
		p=Split(l,r);
		if(type==3){
			Replace(p,(s[0]==‘(‘?1:-1));
			cg[p]=(s[0]==‘(‘?1:-1); lazy[p]=0;
		}
		else{
			if(type==1) Invert(p);
			else Swap(p);
			if(!cg[p]) lazy[p]^=type;
			else if(type==1) cg[p]*=-1;
		}
		Pushup(fa[p]); Pushup(fa[fa[p]]);
	}
	void Build(int &x,int dad,int l,int r){
		static char c;
		if(l>r) return;
		x=(l+r)>>1; fa[x]=dad;
		Build(ch[x][0],x,l,x-1);
		scanf(" %c",&c); key[x]=(c==‘(‘?1:-1);
		Build(ch[x][1],x,x+1,r);
		Pushup(x);
	}
	void BorderBuild(){
		rt=N+1;
		key[N+1]=0; key[N+2]=0;
		ch[N+1][1]=N+2; fa[N+2]=N+1;
		Build(ch[N+2][0],N+2,1,N);
		Pushup(N+2); Pushup(N+1);
	}
	int Query(int l,int r){
		static int p,ANS,nl,nr;
		p=Split(l,r);
		nl=-pmn[p]; nr=smx[p];
		ANS=(nl+1)/2+(nr+1)/2;
		return ANS;
	}
}DT;
int main(){
	freopen("/home/noilinux/Documents/模块学习/2329.in","r",stdin);
	freopen("/home/noilinux/Documents/模块学习/2329.out","w",stdout);
	scanf("%d%d",&N,&M);
	DT.BorderBuild();
	for(int i=1,l,r;i<=M;i++){
		scanf("%s",s); scanf("%d%d",&l,&r);
		if(s[0]==‘Q‘) printf("%d\n",DT.Query(l,r));
		if(s[0]==‘I‘) DT.Modify(l,r,1);
		if(s[0]==‘S‘) DT.Modify(l,r,2);
		if(s[0]==‘R‘) scanf("%s",s),DT.Modify(l,r,3);
	}
	return 0;
}

  

时间: 2024-10-09 06:03:16

●BZOJ 2329 [HNOI2011]括号修复.cpp的相关文章

BZOJ 2329: [HNOI2011]括号修复( splay )

把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, 只是我傻X -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstrin

BZOJ 2329: [HNOI2011]括号修复 [splay 括号]

题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘('和‘)'组成的字符串,位置标号从 1 到 N.对这个字符串有下列四种操作: Replace a b c:将[a,b]之间的所有括号改成 c.例如:假设原来的字符串为:))())())(,那么执行操作 Replace 2 7 ( 后原来的字符串变为:)(((((()(. Swap a b:将[a,b]

【BZOJ】2329: [HNOI2011]括号修复(splay+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=2329 和前一题一样,不就多了个replace操作吗.好,就打一下. 然后交上去wa了.................... 看了题解,好神奇! 记住:以后pushdown的tag要考虑先后顺序! 因为invert和swap操作谁先谁后没有关系,那么考虑invert和replace这两个有冲突的关系 为什么有冲突呢?因为假如你replace的标记在先,invert标记在后,但是invert在pus

2329: [HNOI2011]括号修复

传送魔法 一开始以为可以直接线段树的,好像还是不行--还是得用Spaly,然后就没啥了. #include<cstdio> #include<algorithm> #define MN 210000 using namespace std; inline int read(){ int ca=getchar(),p=0; while (ca<'0'||ca>'9') ca=getchar(); while (ca>='0'&&ca<='9')

bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + 多余的‘(’ /2 [上取整] 把 ‘)’ 看做1,‘(’ 看做-1 那么最少改变次数=最大前缀和/2 [上取整]+ 最小后缀和/2 [上取整] 覆盖标记的优先级高于翻转标记和取反标记 即下放覆盖标记时,同时清空翻转标记和取反标记 且先下放覆盖标记 翻转: 最大前缀和 和 最大后缀和 交换 最小前

BZOJ2329 [HNOI2011]括号修复

把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和 支持区间翻转,反转,覆盖操作...注意如果有覆盖操作,之前的操作全部作废了...于是在下传标记的时候要最后做... 1 /************************************************************** 2 Problem: 2329 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:4252

bzoj2329: [HNOI2011]括号修复 Splay

神题. 用-1表示左括号,1表示右括号,lmax表示从左开始的最大连续和,rmin表示从右开始的最小连续和,答案为(lmax+1)/2+(-rmin+1)/2. Splay维护即可. #include<bits/stdc++.h> #define L(t) (t)->c[0] #define R(t) (t)->c[1] #define Z(t) (L(t)->s+1) #define M (l+r>>1) using namespace std; struct

BZOJ2329 HNOI2011 括号修复 平衡树

题意:给定一个由(,)组成的括号序列,维护:1.将[a,b]修改为同一种半括号  2.将[a,b]翻转  3.将[a,b]的(变为),)变为(  4.求[a,b]最少要添加多少个括号才能合法 题解: 不算太裸的平衡树……论标记的正确打法. 对于一个括号序列,我们总能简化成一个左边全是右括号,右边全是左括号的序列,像酱紫:)))))(((((.当然有可能是没有左括号或者右括号的 我们定义)==-1,(==1.然后我们用打标记的方法来维护从左起的最小序列和lmin和从右起的最大序列和rmax,显然这

矩阵乘法专题4——bzoj 2326 [HNOI2011] 数学作业 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24963747 [原题] 2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 853  Solved: 473 [Submit][Status] Description [分析]我们按数字的位数来划分.对于K位数,我们就可以专门设计一个矩阵来计算. 然后就是注意细节了. [代码] #include