Official

E - Alternating String Editorial by en_translator


For a sequence \(A=(A_1,A_2,\ldots,A_{N-1})\) of length \((N-1)\), let \(A_i=0\) if \(S_i=S_{i+1}\) and \(A_i=1\) if \(S_i\neq S_{i+1}\).

Then a query 1 L R of the first type modifies \(A\) as \(A_{L-1}\leftarrow (1-A_{L-1})\) and \(A_R\leftarrow (1-A_R)\).
Here, if \(L=1\) or \(R=N\), the former or latter update is unneeded, respectively.

On the other hand, a query 2 L R of the second type is Yes if \(A_L=A_{L+1}=\cdots=A_{R-1}=1\), and No otherwise.
Noticing that each \(A_i\) is \(0\) or \(1\), one can decide the answer to be Yes if \(A_L+A_{L+1}+\cdots+A_{R-1}=R-L\), and No otherwise.

These operations can be achieved with a segment tree.
Both queries can be processed in \(O(\log N)\) time each, the problem can be solved in a total of \(O(Q\log N)\) time, which is fast enough.
Thus, the problem has been solved.

When implementing the algorithm above, beware of possibly necessary exception handling when \(N=1\), where the length of \(A\) is \(0\). One can either code exceptional procedure, or allocate a bit longer \(A\).

One can also solve this problem in the same time complexity by managing \(i\) such that \(S_i=S_{i+1}\) in an order set.

Sample code 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;
}

posted:
last update: