公式

H - Alternating String 解説 by mechanicalpenciI


長さ \(N-1\) の数列 \(A=(A_1,A_2,\ldots,A_{N-1})\) を、 \(S_i=S_{i+1}\) ならば \(A_i=0\), \(S_i\neq S_{i+1}\) ならば \(A_i=1\) で定義します。

このとき、\(1\) 種類目のクエリ 1 L R\(A\) に与える変更は、 \(A_{L-1}\leftarrow (1-A_{L-1})\), \(A_R\leftarrow (1-A_R)\)\(2\) つです。
ただし、\(L=1\), \(R=N\) のときはそれぞれ前者、後者の変更を行う必要がありません。

一方で、\(2\) 種類目のクエリ 2 L R の答えは、\(A_L=A_{L+1}=\cdots=A_{R-1}=1\) ならば Yes、そうでないならば No です。
特に、各 \(A_i\)\(0\) または \(1\) の値しかとらないことに注意すると、\(A_L+A_{L+1}+\cdots+A_{R-1}=R-L\) ならば Yes, そうでないならば No として良いです。

これらの操作は、セグメント木を用いて行う事ができます。
必要な計算量はどちらのクエリに対しても \(O(\log N)\) であるため、全体で \(O(Q\log N)\) でこの問題を解く事ができ、十分高速です。
よってこの問題を解く事ができました。

上記の方法を実装する際には、\(N=1\) の時に \(A\) の長さが \(0\) になるため実装方針によっては例外処理が必要になることに注意してください。例外処理、あるいは\(A\) を長めに取得しておく等することによって対処する事ができます。

なお、この問題は \(S_i=S_{i+1}\) であるような \(i\) を順序付き集合などで処理することによっても同様の計算量で解く事ができます。

c++ による実装例:

#include <bits/stdc++.h>
#include <atcoder/segtree>

using namespace std;
using namespace atcoder;

int op(int a, int b) { return (a+b); }

int e() { return 0; }

int main(void){
	int n,q;
	string s;
	int x,l,r;

	cin>>n>>q;
	cin>>s;
	segtree<int, op, e> seg(n+1);
	for(int i=0;i<n-1;i++)if(s[i]!=s[i+1])seg.set(i+1,1);
	for(int i=0;i<q;i++){
		cin>>x>>l>>r;
		if(x==1){
			seg.set(l-1,1-seg.get(l-1));
			seg.set(r,1-seg.get(r));
		}
		else{
			if(seg.prod(l,r)==(r-l))cout<<"Yes"<<endl;
			else cout<<"No"<<endl;
		}
	}
	return 0;
}

投稿日時:
最終更新: