[lnsyoj1158] 淘淘蓝蓝之幻影树

题意

image

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");
    }
}
posted @ 2025-02-07 20:35  是一只小蒟蒻呀  阅读(18)  评论(0)    收藏  举报