\(T\) 組數據c++
給你兩個長度爲 \(n\) 的01串 \(s,f,\)有 \(q\) 次詢問。ui
每次詢問有區間 \([\ l,r\ ]\) ,若是 \([\ l,r\ ]\) 同時包含\(0\)和\(1\),則詢問終止,不然你能夠改變區間\([\ l,r\ ]\) 內嚴格小於 \(len_{lr}\) 的數字。spa
問是否能夠使得詢問不終止,且通過 \(q\) 次詢問後能夠將\(s\)改成\(f\)。code
沒了字符串
發現無法正序推過去(反正我不會),考慮根據詢問逆推。get
那麼對於 \(f\) ,和 \(q_{1},q_{2}\)···\(q_{n}\) ,用 \(l_{i},r_{i}\) 來表示 \(q_{i}\) , \(s_{i}\)表示通過前 \(i\) 次詢問後的字符串 \(s\) 。it
對於第 \(n\) 次詢問,當且僅當 \(s_{n-1}\)中的 \([l_{n},r_{n}]\) 全爲 \(k\) ( \(k\) \(\in\) \((0,1)\) ) ,\(f\) 在 \([l_{n},r_{n}]\) 內(\(k\oplus 1\))的數量\(num_{k\oplus 1}\) \(<\) \(len_{lr}\) 時,class
\(s_{n-1}\) 可轉化 \(f\) 。變量
所以,咱們能夠對於 \(f\) 從 \(n\) 開始向前遍歷詢問。對於 \([l_{i},r_{i}]\) , 將 \([l_{i},r_{i}]\) 內數量較少的數字改成另外一個數字。遍歷
顯然,當 \([l_{i},r_{i}]\) 內 \(num_{1} = num_{0}\) 時,詢問會終止,由於改變量必須嚴格小於區間長度的一半。
遍歷到最後判斷 \(s\) 和通過轉化的 \(f\) 是否相同就好了。
對於區間,查詢和改變問題,咱們能夠用線段樹在 \(log\ n\) 的複雜度下解決。
首先對於 \(f\) 創建線段樹,維護區間內 \(1\) 的數量。
對於區間修改,創建 \(lazy\) 標記,\(-1\) 表示不變,\(0\) 表示 \(lazy\) 下的區間全爲\(0\),\(1\) 表示 \(lazy\) 下的區間全爲\(1\)。
\(pusdown\) 操做:
inline void pushdown(int p,int l,int r) { if(laz[p]==-1)//未被標記跳過 return ; int mid=(l+r)>>1; if(laz[p])//標記爲1 { tr[p<<1]=(mid-l+1); tr[p<<1|1]=(r-mid); laz[p<<1]=laz[p<<1|1]=1; laz[p]=-1; return ; } tr[p<<1]=tr[p<<1|1]=0;//標記爲0 laz[p<<1]=laz[p<<1|1]=0; laz[p]=-1; }
剩下的就是線段樹的基本操做了。
#include<bits/stdc++.h> #define N 240000 using namespace std; int t,n,q; char s[N],f[N]; int ql[N],qr[N],tr[N<<2],laz[N<<2]; inline int read() { char a=0;int w=1,x=0; while(a<'0'||a>'9'){if(a=='-')w=-1;a=getchar();} while(a<='9'&&a>='0'){x=(x<<3)+(x<<1)+(a^48);a=getchar();} return x*w; } inline void pushdown(int p,int l,int r) { if(laz[p]==-1)//未被標記跳過 return ; int mid=(l+r)>>1; if(laz[p])//標記爲1 { tr[p<<1]=(mid-l+1); tr[p<<1|1]=(r-mid); laz[p<<1]=laz[p<<1|1]=1; laz[p]=-1; return ; } tr[p<<1]=tr[p<<1|1]=0;//標記爲0 laz[p<<1]=laz[p<<1|1]=0; laz[p]=-1; } void build(int p,int l,int r)//建樹 { laz[p]=-1; if(l==r) { tr[p]=(f[l]^48); return ; } int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); tr[p]=tr[p<<1]+tr[p<<1|1]; } int que(int p,int l,int r,int L,int R)//查詢1的數量 { if(L<=l&&r<=R) return tr[p]; pushdown(p,l,r); int mid=(l+r)>>1; int ans=0; if(mid>=L) ans+=que(p<<1,l,mid,L,R); if(mid<R) ans+=que(p<<1|1,mid+1,r,L,R); return ans; } void modify(int p,int l,int r,int L,int R,int opt)//區間修改 { if(L<=l&&r<=R) { tr[p]=opt*(r-l+1); laz[p]=opt; return ; } pushdown(p,l,r); int mid=(l+r)>>1; if(mid>=L) modify(p<<1,l,mid,L,R,opt); if(mid<R) modify(p<<1|1,mid+1,r,L,R,opt); tr[p]=tr[p<<1]+tr[p<<1|1]; } int main() { t=read(); while(t--) { n=read(); q=read(); int flag=1; scanf("%s%s",(s+1),(f+1)); for(register int i=1;i<=q;i++) { ql[i]=read(); qr[i]=read(); } build(1,1,n); for(register int i=q;i>=1;i--) { int len=qr[i]-ql[i]+1;//區間長度 int num=que(1,1,n,ql[i],qr[i]);//查詢區間內1的數量 if( num==len-num )//區間內0的數量爲 len-num , 0和1數量相同時不可能成立 { flag=0; break; } modify(1,1,n,ql[i],qr[i],num>(len-num) );//區間修改 } if(!flag) { printf("NO\n"); continue; } for(register int i=1;i<=n;i++) { int num=que(1,1,n,i,i);//取出通過q次詢問後f的第i位 if(num!=(s[i]^48))//判斷f和s是否相等,不相等退出 { flag=0; break; } } if(!flag) { printf("NO\n"); continue; } printf("YES\n"); } return 0; }