P5522 yLOI2019 棠梨煎雪
题目
本题思路:
我们可以运用二进制表示每一位状态,我们定义一个区间,这个区间代表一个字符串,在字符串上,每一个字符串的位置有4种情况,0或1或?或者不存在,可以通过线段树的方式维护区间的一个满足要求的字符串.
首先定义一个数组d1,用来表示这一段区间内,字符串上不为?的位置.再定义d2用来存放位置上放1的位置,d3表示这个区间是否存在满足要求的字符串.
build阶段
当我们找到l==r的时候,我们将此时的字符串进行拆分,将d1,d2进行赋值.
合并的时候,我们先判断左右区间是否不存在满足条件的字符串,如果不存在,我们可以直接将大区间d3也赋值为1(表示不存在).
因为如果存在一个区间不存在,代表这个区间的某个位置既需要为1又需要为0,这显然是不存在的.
之后,我们再进行左右区间合并
先遍历每个位置,在遍历每个位置的时候,我们先判断左右区间是否存在d1不等于0,如果存在,我们在判断这个值是放0还是放1,如果既需要0又需要1,那么,这代表这个字符串的这个位置不符合要求,我们可以直接将d3赋为1,返回.如果这个位置合理,我们将d1,d2赋值.最后,再将这个区间的d1,赋值成左右区间d1合并的值.
update阶段只需要将我们需要更新的区间( 因为修改的区间是同一个,所以l==r)的这个值重新对d1,d2,d3进行赋值即可.其余步骤与build一样
query阶段
先定义一个sum用来存储我们已经查找过的区间,且已经确定该位置不为’?'的值,其次,再定义一个ans,用来表示已经确定为1的位置.
每查找一个区间,我们就先判断是否存在sum和d1的合并是否有为1(二进制)的位置,如果存在那么,我们再遍历每一个位置,如果一个位置,我们已经确定是唯一的值,且正在判断的这个区间的这个位置也是唯一的值,我们再判断这两个位置的是否相同,如果不同,我们就直接判断出这个区间不存在满足的字符串,如果相同,我们将ans与这个区间合并.
#include<iostream>#include<string>using namespace std;int n,m,q;string s;const int N=1e6;#define lc p<<1#define rc p<<1|1int d1[N];int d2[N];int d3[N];int ans;int sum;int res;int flag=0;void build(int p,int l,int r){if(l==r){ cin>>s;for(int i=0;i<n;i++){if(s[i]!='?'){d1[p]|=(1<<i);if(s[i]=='1'){d2[p]|=(1<<i);}}}return;}int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r);if(d3[lc]==1||d3[rc]==1){d3[p]=1;return;}d1[p]=d1[lc]|d1[rc];for(int i=0;i<n;i++){if(((d1[lc]>>i&1)==1)&&((d1[rc]>>i&1)==1)&&((d2[lc]>>i&1)!=(d2[rc]>>i&1))){d3[p]=1;return;}if((d2[lc]>>i&1)==1){d2[p]|=(d2[lc]&(1<<i));}else d2[p]|=(d2[rc]&(1<<i));}}void update(int p,int l,int r,int pos){if(r<pos||l>pos)return;if(l==r){string s;cin>>s;d1[p]=d2[p]=d3[p]=0;for(int i=0;i<n;i++){if(s[i]!='?'){d1[p]|=(1<<i);if(s[i]=='1'){d2[p]|=(1<<i);}}}return;}int mid=l+r>>1;update(lc,l,mid,pos);update(rc,mid+1,r,pos);if(d3[lc]==1||d3[rc]==1){d3[p]=1;return;}d1[p]=d2[p]=d3[p]=0;d1[p]=d1[lc]|d1[rc];for(int i=0;i<n;i++){if(((d1[lc]>>i&1)==1)&&((d1[rc]>>i&1)==1)&&((d2[lc]>>i&1)!=(d2[rc]>>i&1))){d3[p]=1;return;}if((d2[lc]>>i&1)==1){d2[p]|=(d2[lc]&(1<<i));}else d2[p]|=(d2[rc]&(1<<i));}}bool inRange(int l,int r,int L,int R){if(l>=L&&r<=R)return true;return false;}bool outRange(int l,int r,int L,int R){if(l>R||r<L)return true;return false;}void query(int p,int l,int r,int L,int R){if(flag==1)return;if(outRange(l,r,L,R))return;if(inRange(l,r,L,R)){
//这一步一定要先进行判断是否d3[p]==1if(d3[p]==1){flag=true;return;}if(d1[p]|sum){for(int i=0;i<n;i++){if(((d1[p]>>i)&1)&&((sum>>i)&1)&&((d2[p]>>i)&1)!=((ans>>i)&1)){flag=1;return;} ans|=(d2[p]&(1<<i));}sum|=d1[p];}return;}int mid=l+r>>1;query(lc,l,mid,L,R);query(rc,mid+1,r,L,R);}int main(void){cin>>n>>m>>q;build(1,1,m);for(int i=1;i<=q;i++){int opt;cin>>opt;if(opt==1){int ops;cin>>ops;update(1,1,m,ops);}else if(opt==0){int l,r;cin>>l>>r;sum=ans=flag=0;query(1,1,m,l,r);int k=1;if(flag==1)continue;for(int i=0;i<n;i++){if((sum>>i&1)==0)k*=2;}res^=k;}}cout<<res<<endl;return 0;}