[lnsyoj1158] 淘淘蓝蓝之幻影树
题意

sol
若某一方胜利,则设该方战胜的区间为 \([l_i,r_i]\),那么过程可描述为 \(1\) 打败 \([l_1,r_1]\),\(2\) 打败 \(l_2,r_2\)…………\(k\) 打败 \([l_k,r_k]\)。显然,\(k\) 打败 \([l_k,r_k]\)…………\(2\) 打败 \(l_2,r_2\),\(1\) 打败 \([l_1,r_1]\) 与之等价,即顺序的正反对结果没有影响。
因此可以将序列翻转进行计算。设 \(f_{u,j}\) 表示从第 \(u\) 个点开始,会被上方的哪一个点击败,特别地,若全部战胜则 \(f_{u,j}=0\)。那么每次操作可以将序列倒序并进行处理,若最终结果为 \(0\) 则胜利,否则失败。
\[f_{u,j}=\left\{\begin{matrix}
f_{father,j}(win_{j,c[u]}=true) \\
u(win_{j,c[u]}=false)
\end{matrix}\right. \]
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 200005, M = N * 2, K = 25;
int h[N], e[M], ne[M], idx;
int vs[K][K];
int n, m, q;
int c[N], f[N][K];
int w[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs_init(int u, int father){
for (int i = 1; i <= m; i ++ )
if (vs[i][c[u]])
f[u][i] = f[father][i];
else
f[u][i] = u;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs_init(j, u);
}
}
int main(){
// freopen("ex_tree.in", "r", stdin);
memset(h, -1, sizeof h);
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= m; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &vs[i][j]);
for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]);
for (int i = 1; i < n; i ++ ){
int x, y;
scanf("%d%d", &x, &y);
add(x, y), add(y, x);
}
dfs_init(1, 0);
while (q -- ){
int k, p;
scanf("%d%d", &k, &p);
for (int i = 1; i <= k; i ++ ) scanf("%d", &w[i]);
for (int i = k; i; i -- ) p = f[p][w[i]];
if (p) puts("0");
else puts("1");
}
}

浙公网安备 33010602011771号