运用生成树+二分图进行构造:26暑杭电多校 4-02
1002 B. Binary Choice
我们发现,题目已经规定了每种颜色的数量为偶数,但却没有规定每种值的数量为偶数。
但每种值的数量必须为偶数。所以我们可以先思考一下,在不理分组的情况下,是否存在一种办法每种值的个数为偶数。
一个很常见的转化是给 a i , b i a_i,b_i a i , b i 连边,然后让每个点的度数为偶数。
现在转化为一个图论问题。
图论问题涉及边的构造,一般用生成树。
我们随便考虑一个连通块。首先连通块边的数量必须为偶数。
我们再随便考虑一棵dfs生成树。非树边我们随便定向。定完后对于树上的节点,从叶子开始,逐步定树边。现在由每个点的奇偶性就可以决定其往上那条边的方向性。
由于连通块总边数为偶数,所以其他点定完后根节点也必然满足。
由此,我们就设计了一种方案,使每种值的数量为偶数。
接下来要进行分组。
我们可以大胆猜测只要值和颜色的数量为偶数,那么必然存在一种合法分组。不然这题就很难做下去。
我们考虑如果两个点有相同值或相同颜色,就连一条边。同时每个点只连一条值边,一条颜色边。
然后对所有点黑白染色。满足每条边必然是一个白点和一个黑点相连。
我们发现连边后因为是值边和颜色边交替,所以所有环的长度都为偶数。所以必然构成一个二分图。
所以必然可以黑白染色。
总得来说,像这种限制越多,越难下手的构造题,其实构造的多样性是最多的。不要把限制看的太死,不一定必然为唯一构造。
涉及图论的构造,学会用生成树+二分图这两个技巧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 #include <bits/stdc++.h> using namespace std;#ifdef LOCAL #define debug(...) fprintf(stdout, ##__VA_ARGS__) #else #define debug(...) void(0) #endif inline int read () {int x=0 ,f=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )f=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+ (x<<3 )+(ch^48 );ch=getchar ();}return x*f;} #define Z(x) (x)*(x) #define pb push_back #define fi first #define se second #define N 200010 struct node { int a, b, c; }a[N]; int n, m, i, j, k, T;vector<int >ans1, ans2; void Init () { ans1. clear (); ans1. resize (n + 1 ); ans2. clear (); ans2. resize (n + 1 ); unordered_map<int , int >mp; for (i = 1 , k = 0 ; i <= n; ++i) { if (!mp[a[i].a]) mp[a[i].a] = ++k; if (!mp[a[i].b]) mp[a[i].b] = ++k; a[i].a = mp[a[i].a]; a[i].b = mp[a[i].b]; } mp.clear (); for (i = 1 , k = 0 ; i <= n; ++i) { if (!mp[a[i].c]) mp[a[i].c] = ++k; a[i].c = mp[a[i].c]; } } namespace Sol1 { vector<vector<pair<int , int > > >G, son; vector<int >vis, c, b, f, cnt; int i, j, k; void init () { G.clear (); G.resize (2 * n + 10 ); b.clear (); b.resize (2 * n + 10 ); c.clear (); c.resize (2 * n + 10 ); vis.clear (); vis.resize (2 * n + 10 ); son.clear (); son.resize (2 * n + 10 ); cnt.clear (); cnt.resize (2 * n + 10 ); f.resize (2 * n + 10 ); for (i = 1 ; i <= 2 * n; ++i) f[i] = i; } int fa (int x) { if (f[x] == x) return x; return f[x] = fa (f[x]); } void cun (int x, int y, int i) { G[x].pb ({y, i}); G[y].pb ({x, i}); f[fa (x)] = fa (y); } void dfs1 (int x) { vis[x] = 1 ; for (auto t : G[x]) if (!vis[t.fi]) { son[x].pb (t); dfs1 (t.fi); b[t.se] = 1 ; } } void dfs2 (int x) { for (auto t : son[x]) { int y, i = t.se; dfs2 (y = t.fi); if (c[y] & 1 ) { c[y] ^= 1 ; if (a[i].a == y) ans1[i] = 0 ; else ans1[i] = 1 ; } else { c[x] ^= 1 ; if (a[i].a == x) ans1[i] = 0 ; else ans1[i] = 1 ; } } } int main () { init (); for (i = 1 ; i <= n; ++i) cun (a[i].a, a[i].b, i); for (i = 1 ; i <= n; ++i) ++cnt[fa (a[i].a)]; for (i = 1 ; i <= 2 * n; ++i) if (fa (i) == i) { if (cnt[i] & 1 ) return -1 ; dfs1 (i); } for (i = 1 ; i <= n; ++i) if (!b[i]) { c[a[i].a] ^= 1 ; ans1[i] = 0 ; } for (i = 1 ; i <= 2 * n; ++i) if (fa (i) == i) { dfs2 (i); } return 0 ; } } namespace Sol2 { int i, j, k; vector<vector<int > >G; vector<int >vis; void init () { G.clear (); G.resize (2 * n + 1 ); vis.clear (); vis.resize (2 * n + 1 ); } void dfs (int x) { vis[x] = 1 ; for (int y : G[x]) if (!vis[y]) { ans2[y] = (ans2[x] ^ 1 ); dfs (y); } } void cun (int x, int y) { G[x].pb (y); G[y].pb (x); } void main () { init (); map<int , int >mp; for (i = 1 ; i <= n; ++i) { if (ans1[i]) swap (a[i].a, a[i].b); if (!mp[a[i].a]) mp[a[i].a] = i; else cun (mp[a[i].a], i), mp[a[i].a] = 0 ; } mp.clear (); for (i = 1 ; i <= n; ++i) { if (!mp[a[i].c]) mp[a[i].c] = i; else cun (mp[a[i].c], i), mp[a[i].c] = 0 ; } for (i = 1 ; i <= n; ++i) if (!vis[i]) { dfs (i); } } } signed main () { #ifdef LOCAL freopen ("in.txt" , "r" , stdin); freopen ("out.txt" , "w" , stdout); #endif T = read (); while (T--) { n = read (); int ret = 0 ; for (i = 1 ; i <= n; ++i) { a[i].a = read (); a[i].b = read (); a[i].c = read (); } Init (); ret = Sol1 :: main (); if (ret == -1 ) { printf ("-1\n" ); continue ; } Sol2 :: main (); for (i = 1 ; i <= n; ++i) printf ("%d" , ans1[i]); printf ("\n" ); for (i = 1 ; i <= n; ++i) printf ("%d" , ans2[i]); printf ("\n" ); } return 0 ; }