#include <bits/stdc++.h>
#define FF ;
using namespace std;
const int N=1e5+10;
string s1,s2,t1,t2;
//C8，afo了 
int len,ans,c[N][6],qr1[N],qr2[N];//纯浪费空间 
int lowbit(int x){
	return x&(-x);
}
void add(int mk,int x,int val){
	while(x<=len) c[x][mk]+=val,x+=lowbit(x);
}
int query(int mk,int x){
	int res=0;
	while(x) res+=c[x][mk],x-=lowbit(x);
	return res; 
}
struct node{
	int tot1,tot0;
}f1[N],f2[N];
int totu1=1,totu2=1,num1[N],num2[N],c8[N],c9[N];
int main(){
	freopen("edit.in","r",stdin);
	freopen("edit.out","w",stdout);
//	ios::sync_with_stdio(false);
//	cin.tie(NULL);cout.tie(NULL);//没人觉得这两行压在一起很工整吗 
	int T;//多测 记得清空 虽然我也不知道我还能有什么清空的 
	cin>>T;
	while(T--){
		cin>>len;
		cin>>s1>>s2>>t1>>t2;
		bool ok1=1;
		memset(c,0,sizeof(c));
		s1=" "+s1,s2=" "+s2,t1=" "+t1,t2=" "+t2;
		string pbf1="#",pbf2="#";
		ans=0;
		for(int i=2;i<=len;i++){
			if(s1[i]!=s1[i-1])ok1=0;
		}
//		if(ok1){
			ans=0;
			for(int i=1;i<=len;i++){
				if(s1[i]==s2[i]) ans++;
			}
			cout<<ans<<endl;
			continue;
//		}
//放弃了。 
		int pre1=1,pre2=1;
		for(int i=1;i<=len;i++){
			pbf1=pbf1+"#",pbf2=pbf2+"#";
			add(0,i,s1[i]-'0');
			add(1,i,s2[i]-'0');
			if(i==1){
				add(2,i,1);
			}
			else if(t1[i]=='0'){
				add(2,i,i-pre1);
				pre1=i;
			}
			else add(2,i,0);
			if(i==1){
				add(3,i,1);
			}
			else if(t2[i]=='0'){
				add(3,i,i-pre2);
				pre2=i;
			}
			else add(3,i,0);
			if(t1[i]=='0') totu1++;
			if(t2[i]=='0') totu2++;
			if(s1[i]=='0') f1[totu1].tot0++;
			else f1[totu1].tot1++;
			if(s2[i]=='0') f2[totu2].tot0++;
			else f2[totu2].tot1++;
			num1[i]=totu1,num2[i]=totu2;
		}
		qr1[len+1]=len,qr2[len+1]=len;
		for(int i=len;i>=1;i--){
			if(t1[i]=='1') qr1[i]=qr1[i+1];
			else qr1[i]=i;
			if(t2[i]=='1') qr2[i]=qr2[i+1];
			else qr2[i]=i;
		}
		pbf1=pbf1+"#";pbf2=pbf1;
//		for(int i=1;i<=len;i++) cout<<query(3,i)<<endl;
		for(int i=1;i<=len;i++){
			FF
			int tl1=query(2,i),tl2=query(3,i),tr1=qr1[i],tr2=qr2[i];FF
			int cnt1=query(0,tr1)-query(0,tl1-1);FF
			int cnt2=query(1,tr2)-query(1,tl2-1);FF
//			cout<<"cnt1:"<<tr1<<" "<<tl1<<" "<<cnt1<<endl;
//			cout<<"cnt2:"<<tr2<<" "<<tl2<<" "<<cnt2<<endl;
			if(tl1==tr1 && tl2==tr2){//说明这个点两边都不让动 
				pbf1[tl1]=s1[tl1],pbf2[tl2]=s2[tl2];
			}
			else if(tl1==tr1){//s1不能动,看看s2的区间里有没有和它一样的 
				cnt2=query(1,tr2-1)-query(1,tl2);
//				cout<<i<<" "<<cnt1<<" "<<cnt2<<" "<<tr2-tl2+1<<endl; 
				if(cnt1==1){
					if(cnt2>0){
//						cout<<"1i="<<i<<endl;
						pbf1[tl1]=s1[tl1],pbf2[tl1]=s1[tl1];FF
						if(pbf2[tl1]=='0' && s2[tl1]=='1'){
							cout<<__LINE__<<endl;
							f2[num2[tl1]].tot0++,f2[num2[tl1]].tot1--;
							f2[num2[tl1]-1].tot0--,f2[num2[tl1]-1].tot1++;
						}
						if(pbf2[tl1]=='1' && s2[tl1]=='0'){
							f2[num2[tl1]].tot0--,f2[num2[tl1]].tot1++;
							f2[num2[tl1]-1].tot0++,f2[num2[tl1]-1].tot1--;
						}
					}
					else pbf1[tl1]=s1[tl1],pbf2[tl1]=s2[tl1];
				} 
				else{FF
					if(cnt2<tr2-tl2+1){
//						cout<<"2i="<<i<<endl;
						pbf1[tl1]=s1[tl1],pbf2[tl1]=s1[tl1];
						if(pbf2[tl1]=='0' && s2[tl1]=='1'){
//							cout<<__LINE__<<endl;
							f2[num2[tl1]].tot0++,f2[num2[tl1]].tot1--;
							f2[num2[tl1]-1].tot0--,f2[num2[tl1]-1].tot1++;
						}
						if(pbf2[tl1]=='1' && s2[tl1]=='0'){
							f2[num2[tl1]].tot0--,f2[num2[tl1]].tot1++;
							f2[num2[tl1]-1].tot0++,f2[num2[tl1]-1].tot1--;
						}
					}
					else pbf1[tl1]=s1[tl1],pbf2[tl1]=s2[tl1];
				}
				//把s2的l修改到这个点
				add(3,i,i-tl2);
				add(3,tr2,tl2-i); 
//				cout<<"case1,"<<pbf1<<" "<<pbf2<<endl;
			}
			else if(tl2==tr2){//s1不能动,看看s2的区间里有没有和它一样的 
			cnt1=query(0,tr1-1)-query(0,tl1);
//			cout<<i<<" "<<cnt1<<" "<<cnt2<<" "<<tr1-tl1+1<<" "<<tr1-1<<" "<<tl1+1<<endl; FF
				if(cnt2==1){
					if(cnt1>0){
//						cout<<"3i="<<i<<endl;
						pbf2[tl2]=s2[tl2],pbf1[tl2]=s2[tl2];
//						cout<<"tl2="<<tl2<<" "<<pbf1[tl2]<<endl;
						if(pbf1[tl2]=='0' && s1[tl2]=='1'){
//							cout<<__LINE__<<endl;
							f1[num1[tl2]].tot0++,f1[num1[tl2]].tot1--;
							f1[num1[tl2]-1].tot0--,f1[num1[tl2]-1].tot1++;
						}
						if(pbf1[tl2]=='1' && s1[tl2]=='0'){
//							cout<<__LINE__<<endl;
							f1[num1[tl2]].tot0--,f1[num1[tl2]].tot1++;
							f1[num1[tl2]-1].tot0++,f1[num1[tl2]-1].tot1--;
						}
					}
					else pbf2[tl2]=s2[tl2],pbf1[tl2]=s1[tl2];
				} 
				else{
					if(cnt1<tr1-tl1+1){
//						cout<<"4i="<<i<<endl;
						pbf2[tl2]=s2[tl2],pbf1[tl2]=s2[tl2];
						if(pbf1[tl2]=='0' && s1[tl2]=='1'){
							f1[num1[tl2]].tot0++,f1[num1[tl2]].tot1--;
							f1[num1[tl2]-1].tot0--,f1[num1[tl2]-1].tot1++;
						}
						if(pbf1[tl2]=='1' && s1[tl2]=='0'){
							f1[num1[tl2]].tot0--,f1[num1[tl2]].tot1++;
							f1[num1[tl2]-1].tot0++,f1[num1[tl2]-1].tot1--;
						}
					}
					else pbf2[tl2]=s2[tl2],pbf1[tl2]=s1[tl2];
				}
				//把s2的l修改到这个点
				add(2,i,i-tl1); 
				add(2,tr1,tl1-i); 
//				cout<<"case2,"<<pbf1<<" "<<pbf2<<endl;
			}
		}
		ans=0;
		for(int i=1;i<=len;i++){
			if(pbf1[i]!='#'){
				if(pbf1[i]==pbf2[i]) ans++;
				cout<<i<<" "<<ans<<endl;
				continue;
			}
			int tmp1=f1[num1[i]].tot0,tmp2=f1[num1[i]].tot1;
			int tmp3=f2[num2[i]].tot0,tmp4=f2[num2[i]].tot1;
			if(tmp1&&tmp3){
				ans++;
				f1[num1[i]].tot0--;f2[num2[i]].tot0--;
			}
			else if(tmp2&&tmp4){
				ans++;
				f1[num1[i]].tot1--;f2[num2[i]].tot1--;
			}
			cout<<ans<<endl;
		}
		cout<<ans<<endl;
	}
	return 0;
}
/*
我就知道会考点字符串，c8
反正这里把固定的字符当边界然后每一段里面的字符都是可以任意移动的吧
这个是个贪心还是dp，我觉得可以贪心
不管了321上暴力
老天啊我真的想要NOIP1=和NGOI1=
咦我是不是可以预处理一个前缀和（是不是单点修改区间查询啊？ 
新建一个cpp测试一下我的树状数组是否正确(ok)。 
考点dev的格式化怎么是好的 
线性处理出来 每个点的左边界和右边界(ok) 
我想的是，每次遇到当前字符不能动的就尽量满足它，如果两边都不能动就认命
经过这样的处理可以让两边不能动的区域变成一样的 
然后一样长的能动的区域ans+=min(能动的1，能动的0)
这题怎么有点像我看kpop舞台拉郎：这里有1，这里有0，好了我要让他们配对 
我要哭出来了怎么这么困难，你们是不是都会了
@poembelief @Jasmine_Xu 
求你们了救救我吧
AFO了真AFO了疑似成为全市最菜女选手 
*/
