codeforces基础题——#357(div2) D

来源:互联网 发布:linux 分辨率 编辑:程序博客网 时间:2024/05/22 15:26

#357(div2) D

题目大意:有一颗n(0 <= n <= 100000)个节点的树, 每个节点要给他的一个祖先(它到根的路径上所有的点, 包括他自己)送礼物。现在已知每个点要给那个祖先送礼, 求一个序列, 使得如果x要给祖先y送礼, 那么在序列中y必须出现在x的所有其他祖先之前, 即x会给序列中出现的第一个祖先送礼。题解: (这题题意理解了好半天…)我们发现,如果y是x的一个儿子, y的祖先的集合之比x的多了一个y本身, 其他都一样祖先一样, 所以如果y不给自己送礼, 那么x和y就只能送给同一个人。 所以我们只要判断每个点是否给自己送礼或与父亲送给同一个人就能判断是否尊在合法序列。如果合法就直接dfs构造出来即可。
#include <cstdio>#include <cstring>using namespace std;struct Edge{    int to, next;}edge[100100];int head[100100], num = 0, c[100100];void add_edge(int a, int b){    edge[++ num].to = b;    edge[num].next = head[a], head[a] = num;}bool vis[100100], flag = false;int ans[100100], cnt = 0, d[100100];void dfs(int x){    for (int i = head[x]; i != -1; i = edge[i].next){        dfs(edge[i].to);        if (c[edge[i].to] != edge[i].to && c[edge[i].to] != c[x]) flag = true;    }    if ((!vis[c[x]]) && (c[x] == x)) ans[++ cnt] = c[x], vis[c[x]] = true;}int main(){    int n, m, x, y;    scanf("%d %d", &n, &m);    memset(head, -1, sizeof(head));    for (int i = 1; i <= m; i ++){        scanf("%d %d", &x, &y);        add_edge(x, y);        d[y] ++;    }    for (int i = 1; i <= n; i ++) scanf("%d", &c[i]);    for (int i = 1; i <= n; i ++)        if (!d[i]) dfs(i);    if (flag) printf("-1\n");    else {        printf("%d\n", cnt);        for (int i = 1; i <= cnt; i ++) printf("%d\n", ans[i]);    }    return 0;}
0 0
原创粉丝点击