赞
踩
T T T 组数据
给你两个长度为 n n n 的01串 s , f , s,f, s,f,有 q q q 次询问。
每次询问有区间 [ l , r ] [\ l,r\ ] [ l,r ] ,如果 [ l , r ] [\ l,r\ ] [ l,r ] 同时包含 0 0 0和 1 1 1,则询问终止,否则你可以改变区间 [ l , r ] [\ l,r\ ] [ l,r ] 内严格小于 l e n l r len_{lr} lenlr 的数字。
问是否可以使得询问不终止,且经过 q q q 次询问后可以将 s s s改为 f f f。
没了
发现没法正序推过去(反正我不会),考虑根据询问逆推。
那么对于 f f f ,和 q 1 , q 2 q_{1},q_{2} q1,q2··· q n q_{n} qn ,用 l i , r i l_{i},r_{i} li,ri 来表示 q i q_{i} qi , s i s_{i} si表示经过前 i i i 次询问后的字符串 s s s 。
对于第 n n n 次询问,当且仅当 s n − 1 s_{n-1} sn−1中的 [ l n , r n ] [l_{n},r_{n}] [ln,rn] 全为 k k k ( k k k ∈ \in ∈ ( 0 , 1 ) (0,1) (0,1) ) , f f f 在 [ l n , r n ] [l_{n},r_{n}] [ln,rn] 内( k ⊕ 1 k\oplus 1 k⊕1)的数量 n u m k ⊕ 1 num_{k\oplus 1} numk⊕1 < < < l e n l r len_{lr} lenlr 时,
s n − 1 s_{n-1} sn−1 可转化 f f f 。
因此,我们可以对于 f f f 从 n n n 开始向前遍历询问。对于 [ l i , r i ] [l_{i},r_{i}] [li,ri] , 将 [ l i , r i ] [l_{i},r_{i}] [li,ri] 内数量较少的数字改为另一个数字。
显然,当
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri] 内
n
u
m
1
=
n
u
m
0
num_{1} = num_{0}
num1=num0 时,询问会终止,因为改变量必须严格小于区间长度的一半。
遍历到最后判断 s s s 和经过转化的 f f f 是否相同就行了。
对于区间,查询和改变问题,我们可以用线段树在 l o g n log\ n log n 的复杂度下解决。
首先对于 f f f 建立线段树,维护区间内 1 1 1 的数量。
对于区间修改,建立 l a z y lazy lazy 标记, − 1 -1 −1 表示不变, 0 0 0 表示 l a z y lazy lazy 下的区间全为 0 0 0, 1 1 1 表示 l a z y lazy lazy 下的区间全为 1 1 1。
p u s d o w n pusdown 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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。