CF1340F Nastya and CBS

Nastya and CBS

A string \(s\) is given. It consists of \(k\) kinds of pairs of brackets. Each bracket has the form \(t\) — it is an integer, such that \(1 \leq |t| \leq k\). If the bracket has a form \(t\), then:

  • If \(t > 0\), then it's an opening bracket of the type \(t\).

  • If \(t < 0\), then it's a closing bracket of the type \(-t\).

Thus, there are \(k\) types of pairs of brackets in total.

The queries need to be answered:

  1. Replace the bracket at position \(i\) with the bracket of the form \(t\).

  2. Check if the substring from the \(l\)-th to \(r\)-th position (including) is the correct bracket sequence.

\(1\leq n,q\leq 10^5\).

题解

考虑维护区间前缀未匹配上的右括号和后缀未匹配上的左括号。

合并区间的时候把左边区间的后缀右括号和右边区间的前缀左括号抵消掉即可。

考虑分块,然后\(O(qn)\)\(10^5\)。因为memcpy常数很小,所以即使是\(10^5\)个左括号复制\(10^5\)次,还是能跑出来。

CO int N=1e5+10,M=320;
int seq[N],lab[N];
int L[M],R[M],ok[M];
int F[M][N],G[M][N];

void build(int x){
	ok[x]=1,F[x][0]=G[x][0]=0;
	static int stk[N];
	int top=0;
	for(int i=L[x];i<=R[x];++i){
		if(seq[i]>0) stk[++top]=seq[i];
		else if(top){
			if(stk[top]!=-seq[i]){
				ok[x]=0; return;
			}
			--top;
		}
		else F[x][++F[x][0]]=seq[i];
	}
	memcpy(G[x]+1,stk+1,sizeof(int)*top),G[x][0]=top;
}
bool query(int l,int r){
	static int stk[N];
	int top=0;
	if(lab[l]==lab[r]){
		for(int i=l;i<=r;++i){
			if(seq[i]>0) stk[++top]=seq[i];
			else{
				if(!top or stk[top]!=-seq[i]) return 0;
				--top;
			}
		}
		return !top;
	}
	for(int i=l;i<=R[lab[l]];++i){
		if(seq[i]>0) stk[++top]=seq[i];
		else{
			if(!top or stk[top]!=-seq[i]) return 0;
			--top;
		}
	}
	for(int x=lab[l]+1;x<=lab[r]-1;++x)if(!ok[x]) return 0;
	for(int x=lab[l]+1;x<=lab[r]-1;++x){
		if(top<F[x][0]) return 0;
		for(int i=1;i<=F[x][0];++i){
			if(stk[top]!=-F[x][i]) return 0;
			--top;
		}
		memcpy(stk+top+1,G[x]+1,sizeof(int)*G[x][0]),top+=G[x][0];
	}
	for(int i=L[lab[r]];i<=r;++i){
		if(seq[i]>0) stk[++top]=seq[i];
		else{
			if(!top or stk[top]!=-seq[i]) return 0;
			--top;
		}
	}
	return !top;
}

int main(){
	int n=read<int>(),k=read<int>();
	for(int i=1;i<=n;++i) read(seq[i]);
	int m=ceil(pow(n,0.55));
	for(int i=1;i<=n;++i) lab[i]=(i+m-1)/m;
	for(int i=1;i<=lab[n];++i) L[i]=R[i-1]+1,R[i]=min(i*m,n);
	for(int i=1;i<=lab[n];++i) build(i);
	for(int q=read<int>();q--;){
		if(read<int>()==1){
			int i=read<int>();
			read(seq[i]),build(lab[i]);
		}
		else{
			int l=read<int>(),r=read<int>();
			puts(query(l,r)?"Yes":"No");
		}
	}
	return 0;
}

正确的做法是在线段树上维护这些括号序列的hash值,抵消的时候递归长度大的一侧查询对应长度的hash值。

时间复杂度\(O(n\log^2 n)\)https://codeforces.ml/contest/1340/submission/77902949

或者你像题解那样也行。

posted on 2020-04-25 11:46  autoint  阅读(355)  评论(2编辑  收藏  举报

导航