[lnsyoj1158] 淘淘蓝蓝之幻影树

题意

image

sol

若某一方胜利,则设该方战胜的区间为 [li,ri],那么过程可描述为 1 打败 [l1,r1]2 打败 l2,r2…………k 打败 [lk,rk]。显然,k 打败 [lk,rk]…………2 打败 l2,r21 打败 [l1,r1] 与之等价,即顺序的正反对结果没有影响。
因此可以将序列翻转进行计算。设 fu,j 表示从第 u 个点开始,会被上方的哪一个点击败,特别地,若全部战胜则 fu,j=0。那么每次操作可以将序列倒序并进行处理,若最终结果为 0 则胜利,否则失败。

fu,j={ffather,j(winj,c[u]=true)u(winj,c[u]=false)

代码

#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 @   是一只小蒟蒻呀  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示