红与蓝
Time Limit: 10 Sec Memory Limit: 256 MBDescription
Input
Output
Sample Input
2
2
0 1
-1 -1
2
0 1
-1 1
Sample Output
1 2
-1
HINT
Main idea
每个节点有红色、蓝色或者无色,给定了若干叶子节点的颜色,非叶子节点的颜色定义为所有儿子中颜色出现次数最多的一个,若一样则无色。叶子节点无色则可以染色,红色先手,蓝色接着轮流染色,最后若根为红色则胜利否则失败。胜利的话还要求输出可行方案。
Source
我们可以先O(n)求出在不动叶子节点情况下每一个点的颜色,由于每个一个点只有奇数个儿子,且红色先手。那么这时候如果根节点为红色或者无色则必胜,蓝色则必败。
然后我们分情况讨论,蓝色就直接输出“-1”,结束即可。如果根是红色的话,显然染色对于答案是没有什么影响的,所以所有无色的叶子节点都可以是解。
现在我们来讨论根无色的情况:我们计算每一个点中儿子的蓝色个数和红色个数,如果一个点是 (蓝色,且蓝色个数=红色个数+1) 或者 (无色,蓝色个数=红色个数)则可以往下递归,找到叶子节点为无色则可以是解。我们来解释一下:
1. 蓝色,蓝色个数=红色个数+1:如果往下走有可染色的叶子节点,那么必然逼着蓝色接着染,否则蓝色就输了。这个点的颜色就会是:无、蓝、无……由于红色先手,所以最后这个点是可以变成无色的,因为递归做到这里,所以这个点的父亲节点是白色的,然后这个点变为了白色,它的父亲就少了一个蓝色儿子,就变成红色了。
2. 无色,蓝色个数=红色个数:如果往下走有可染色的叶子节点,那么这一条无色链上都会变成红色的,显然可行。
这样我们暴力递归往下讨论,就解决了这个问题。
Code
1 #include<iostream>
2 #include<algorithm>
3 #include<cstdio>
4 #include<cstring>
5 #include<cstdlib>
6 #include<cmath>
7 using namespace std;
8
9 const int ONE = 100005;
10
11 int T;
12 int n,x,root;
13 int Val[ONE];
14 int next[ONE],first[ONE],go[ONE],tot;
15 int ans_num,Ans[ONE];
16
17 void Add(int u,int v)
18 {
19 next[++tot]=first[u]; first[u]=tot; go[tot]=v;
20 }
21
22 int get()
23 {
24 int res,Q=1; char c;
25 while( (c=getchar())<48 || c>57)
26 if(c=='-')Q=-1;
27 if(Q) res=c-48;
28 while((c=getchar())>=48 && c<=57)
29 res=res*10+c-48;
30 return res*Q;
31 }
32
33 void Deal_first(int u)
34 {
35 for(int e=first[u];e;e=next[e])
36 {
37 int v=go[e];
38 Deal_first(v);
39 Val[u] += Val[v];
40 }
41 if(Val[u] < 0) Val[u] = -1;
42 else if(Val[u] > 0) Val[u] = 1;
43 }
44
45 void Dfs(int u)
46 {
47 if(!Val[u] && !first[u])
48 Ans[++ans_num] = u;
49
50 for(int e=first[u];e;e=next[e])
51 {
52 int v=go[e];
53 int tot=0;
54 for(int i=first[v];i;i=next[i])
55 tot+=Val[go[i]];
56 if(tot==0 || tot==-1) Dfs(v);
57 }
58 }
59
60 void Solve()
61 {
62 n=get();
63 tot=0; memset(first,0,sizeof(first));
64 for(int i=1;i<=n;i++)
65 {
66 x=get();
67 if(!x) root=i;
68 else Add(x,i);
69 }
70
71 for(int i=1;i<=n;i++)
72 {
73 Val[i]=get();
74 if(Val[i]==0) Val[i]=1;
75 else if(Val[i]==1) Val[i]=-1;
76 else Val[i]=0;
77 }
78
79 Deal_first(root);
80 if(Val[root] < 0)
81 {
82 printf("-1");
83 return;
84 }
85 else
86 {
87 ans_num=0;
88 if(Val[root]==0) Dfs(root),sort(Ans+1,Ans+ans_num+1);
89 if(Val[root]==1) for(int i=1;i<=n;i++) if(!Val[i] && !first[i]) Ans[++ans_num]=i;
90
91 printf("%d ",ans_num);
92 for(int i=1;i<=ans_num;i++)
93 printf("%d ",Ans[i]);
94 }
95 }
96
97 int main()
98 {
99 T=get();
100 while(T--)
101 Solve(),printf("
");
102 }