区间操作考虑用线段树维护。
建 n ∗ 2 n*2 n∗2棵线段树,前 n n n棵线段树维护每个串的第i位是否是0。
后 n n n棵线段树维护每个串的第i位是否是1。
如果是问号的话,直接跳过就好(通过1和0能看出是否是问号)。
然后分三种情况统计答案:
1.有1也有0,不可能, a n s = 0 ans=0 ans=0
2.只有1或0,一种情况, a n s ans ans不变。
3.既没有0也没有1,两种情况 a n s ∗ = 2 ans*=2 ans∗=2
像这样这棵线段树。
但是这样会很慢。
考虑状压。
这样只用开两棵线段树,一个存零,一个存一。
把状态压缩成一个 i n t int int,最多30位,转换成十进制 i n t int int能存下。
然后的建树、查询、更改操作其实就是类似一个模板。
建树:
void build(int hao,int l,int r)
{
if(l==r)
{
for(int i=1;i<=n;i++)
{
if(s[l][i]=='?')//问号跳过
{
continue;
}
flag[hao][s[l][i]-'0']|=(1<<(i-1));//状压
}
return;
}
int mid=(l+r)/2;
build(hao<<1,l,mid);
build(hao<<1|1,mid+1,r);
flag[hao][0]=flag[hao<<1][0]|flag[hao<<1|1][0];
flag[hao][1]=flag[hao<<1][1