P11234 [CSP-S 2024] 擂台游戏
观察到补充选手很强,补充选手作为擂主时可控制是否取胜。
观察到一个人贡献到
考虑计算
算
- 若擂主是
v 且a_{p_v} 达到父亲深度要求,那么g_i\gets\min(g_i,f_{v}) 。即v 子树必须派补充选手。 - 若擂主是
u 且a_i 没达到u 父亲深度要求,那么g_i\gets\min(g_i,i) 。即i 必须是补充选手。
现在是
设
算完后
常数小优化:只有
#include<bits/stdc++.h>
using namespace std;
int read(){
int x = 0; bool f = 0; char c = getchar();
for(;!isdigit(c);c = getchar()) f |= (c == '-');
for(;isdigit(c);c = getchar()) x = x * 10 + (c - '0');
return f ? -x : x;
}
using ll = long long;
const int N = 3e5 + 5;
int C,n,m,k,K,A[N],a[N],b[N],c[N],clen,V[10];
int d[N],f[N],g[N],h[N],P[N],o[N],rt,n0,n1;
ll ans[N],ans1[N];
char s[N];
void build(int p){
if(p * 2 > K) return P[p] = f[p] = p - (1 << k) + 1,void();
int lc = p * 2,rc = lc + 1;
build(lc),build(rc);
d[p] = d[lc] + 1;
P[p] = c[p] ? (a[P[rc]] >= d[p] ? P[rc] : P[lc]) : (a[P[lc]] >= d[p] ? P[lc] : P[rc]);
f[p] = c[p] ? f[rc] : (a[P[lc]] >= d[p] ? f[lc] : f[rc]);
}
void dfs(int p){
if(g[p] <= n1) return;
if(p * 2 > K){
int q = p - (1 << k) + 1;
g[p] = min(g[p],a[q] < h[p] ? q : n0 + 1),o[q] = rt;
return;
}
int lc = p * 2,rc = lc + 1;
g[lc] = g[rc] = g[p],h[lc] = h[rc] = h[p];
if(!c[p] && a[P[lc]] >= d[p]) g[rc] = min(g[rc],f[lc]);
if(!c[p]) h[lc] = max(h[lc],d[p]);
if(c[p] && a[P[rc]] >= d[p]) g[lc] = min(g[lc],f[rc]);
if(c[p]) h[rc] = max(h[rc],d[p]);
dfs(lc),dfs(rc);
}
int main(){
n = read(),m = read();
for(int i = 1;i <= n;++i) A[i] = read();
for(int i = 1;i <= m;++i) b[i] = read();
k = __lg(n - 1) + 1,K = (1 << (k + 1)) - 1;
for(int i = 1;i <= k;++i){
scanf("%s",s + 1);
for(int j = strlen(s + 1);j;--j) c[++clen] = s[j] - '0';
}
reverse(c + 1,c + clen + 1);
for(C = read();C--;){
for(int i = 0;i < 4;++i) V[i] = read();
for(int i = 1;i <= n;++i) a[i] = A[i] ^ V[i % 4],ans[i] = 0;
build(1);
for(int i = 1;i <= (1 << k);++i) ans[i] = 0,o[i] = -1;
ans[1] = 1;
for(int j = 0;j < k;++j){
rt = 1 << j,n0 = 1 << (k - j),n1 = 1 << (k - j - 1);
g[rt] = n0 + 1,h[rt] = 0,dfs(rt);
for(int i = n0;i >= 1;--i) if(o[i] == rt){
int t = g[i + (1 << k) - 1] - 1;
if(t <= n0 && t > n1) ans[t] += i;
}
for(int i = n0 - 1;i > n1;--i) ans[i] += ans[i + 1];
}
ll sum = 0;
for(int i = 1;i <= m;++i) sum ^= ans[b[i]] * i;
printf("%lld\n",sum);
}
return 0;
}