用的是 lsj2009 那篇题解的思路,时间复杂度带一个 log。不知道为什么就 WA 了
#include<bits/stdc++.h>
using namespace std;
int n, m, k, nown, a[400005], a2[400005], c[400005];
char s[20][400005];
struct node {
int d; // 擂主
int g; // 这个节点是第几场比赛
int w; // 自由选手能力值为 inf 时的 winner
int maxn; // 想让一个自由选手成为 winner,n' 最大是多少
} t[400005];
int pos[400005]; // 每个人对应的节点
int cnt[20];
void init(int u, int dep) {
++cnt[dep];
if(dep==k) {
pos[cnt[dep]]=u;
t[u].g = cnt[dep];
return;
}
t[u].d = s[dep][cnt[dep]]^48;
init(u<<1, dep+1), init(u<<1|1, dep+1);
}
void dfs(int u, int dep) {
if(dep==k) {
t[u].w=t[u].g, t[u].maxn=t[u].g-1;
return;
}
dfs(u<<1, dep+1), dfs(u<<1|1, dep+1);
int s1=u<<1|(t[u].d), s2=s1^1;
// s1 为当擂主的儿子,s2 为另一个儿子
if(a[t[s1].w] >= k-dep) t[u].w=t[s1].w, t[u].maxn=t[s1].maxn;
else t[u].w=t[s2].w, t[u].maxn=t[s2].maxn;
t[u].maxn=max(t[u].maxn, t[s1].maxn);
}
int ans[400005];
void add(int l, int r, int val) { // 区间加
if(l<=r) ans[l]+=val, ans[min(r, nown)+1]-=val;
}
void calc() {
nown=1<<k;
for(int i=0; i<=nown; i++) ans[i]=0;
for(int i=n+1; i<=nown; i++) a[i]=1e9; // 自由选手能力无穷大
dfs(1, 0);
add(1, 1, 1);
for(int i=1; i<=nown; i++) {
int u=pos[i], dep=0, val=1e9;
// 分析普通选手
if(i<=n) {
while(u>1) {
int f=u>>1;
++dep;
if((u&1) == t[f].d) {
if(a[i]<dep) break;
} else {
if(a[t[u^1].w] >= dep) {
// 被普通选手干掉了,所以只能把希望寄托在自由选手身上了
val=min(val, t[u^1].maxn);
}
}
if(i <= (1<<dep)) {
add(max((1<<(dep-1))+1, i), min(val, 1<<dep), i);
}
u=f;
}
}
// 分析自由选手
u=pos[i], dep=0, val=1e9;
while(u>1) {
int f=u>>1;
++dep;
if((u&1) != t[f].d) {
if(a[t[u^1].w] >= dep) {
val=min(val, t[u^1].maxn);
}
}
if(i <= (1<<dep)) {
add((1<<(dep-1))+1, min(val, i-1), i);
break;
}
u=f;
}
}
for(int i=1; i<=nown; i++) ans[i]+=ans[i-1];
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d", &a2[i]);
for(int i=1; i<=m; i++) scanf("%d", &c[i]);
while((1<<k) < n) k++;
for(int i=k-1; i>=0; i--) scanf("%s", s[i]+1);
init(1, 0);
int T;
scanf("%d", &T);
while(T--) {
int x[4];
scanf("%d%d%d%d", x, x+1, x+2, x+3);
for(int i=1; i<=n; i++) a[i]=a2[i]^x[i&3];
calc();
long long r=0;
for(int i=1; i<=m; i++) r^=i*ans[c[i]];
printf("%d\n", r);
}
return 0;
}