#include <bits/stdc++.h>
using namespace std;
/**
* PROBLEM: Tree Perfect Matching
*
* Given a tree, for each node, check if its subtree can be perfectly paired.
*
* "Perfectly paired" means:
* - Every node matches with exactly one other node
* - Matched nodes must be connected by an edge
*
* IMPORTANT ASSUMPTION:
* - This solution roots the tree at node 0 (after converting to 0-based indexing)
* - "Subtree of node u" means the subtree when viewing the tree rooted at 0
* - If the problem specifies a different root, you must change the root node!
*
* Example:
* 0
* / \
* 1 2
*
* Subtree at 0: {0,1,2} - node 0 pairs with 1, but 2 is alone -> NO
* We need even nodes AND valid pairing structure
*/
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Read tree size
int n;
if (!(cin >> n)) return 0;
// ============================================================
// Read edges and detect if nodes start from 0 or 1
// ============================================================
vector<pair<int, int>> edges;
int min_node = INT_MAX;
int max_node = INT_MIN;
for (int i = 0; i < n - 1; i++) {
int a, b;
cin >> a >> b;
edges.push_back({a, b});
min_node = min({min_node, a, b});
max_node = max({max_node, a, b});
}
// Improved indexing detection:
// - If max_node == n, definitely 1-based (n is invalid in 0-based)
// - If min_node == 1 and max_node == n, definitely 1-based
// - If min_node == 0, definitely 0-based
bool starts_from_one = (max_node == n) || (min_node == 1 && max_node == n);
// ============================================================
// Build the tree (convert to 0-based indexing)
// ============================================================
vector<vector<int>> tree(n);
for (auto [a, b] : edges) {
// Convert to 0-based if needed
if (starts_from_one) {
a--;
b--;
}
// Validate indices after conversion
if (a < 0 || a >= n || b < 0 || b >= n) {
return 0; // Invalid input
}
tree[a].push_back(b);
tree[b].push_back(a);
}
// ============================================================
// Root the tree at node 0
// ============================================================
// NOTE: If the problem specifies a different root, change this!
const int ROOT = 0;
vector<int> parent(n, -1);
vector<int> nodes; // All nodes in visit order
// Use DFS to establish parent-child relationships
stack<int> s;
s.push(ROOT);
parent[ROOT] = ROOT; // Root is its own parent
while (!s.empty()) {
int node = s.top();
s.pop();
nodes.push_back(node);
for (int next : tree[node]) {
if (parent[next] == -1) { // Not visited yet
parent[next] = node;
s.push(next);
}
}
}
// Build list of children for each node
vector<vector<int>> kids(n);
for (int i = 0; i < n; i++) {
if (i != ROOT && parent[i] >= 0) {
kids[parent[i]].push_back(i);
}
}
// ============================================================
// Solve with Dynamic Programming
// ============================================================
/**
* Two states for each node:
*
* paired[node] = 1 if subtree can be matched with this node
* paired to one of its kids
*
* alone[node] = 1 if subtree can be matched leaving this node
* free (to pair with parent later)
*
* Note: Using vector<char> instead of vector<bool> for performance
* (vector<bool> is a specialized bitset that can be slower)
*/
vector<char> paired(n, 0);
vector<char> alone(n, 0);
// Process from bottom to top (kids before parents)
reverse(nodes.begin(), nodes.end());
for (int node : nodes) {
int num_kids = kids[node].size();
// --------------------------------------------------------
// Can this node be left alone?
// --------------------------------------------------------
// Yes, if ALL kids are paired within their own subtrees
alone[node] = 1;
for (int kid : kids[node]) {
if (!paired[kid]) {
alone[node] = 0;
break;
}
}
// --------------------------------------------------------
// Can this node pair with a kid?
// --------------------------------------------------------
// Yes, if we can find ONE kid to pair with, and all
// OTHER kids are paired in their subtrees
if (num_kids == 0) {
// Leaf - no kids to pair with
paired[node] = 0;
} else {
// Try pairing with each kid
// Use prefix/suffix to quickly check "all others paired"
// before[i] = are all kids with index < i paired?
// after[i] = are all kids with index > i paired?
vector<char> before(num_kids + 1, 1);
vector<char> after(num_kids + 1, 1);
for (int i = 0; i < num_kids; i++) {
before[i + 1] = before[i] && paired[kids[node][i]];
}
for (int i = num_kids - 1; i >= 0; i--) {
after[i] = after[i + 1] && paired[kids[node][i]];
}
// Check each kid as a potential partner
paired[node] = 0;
for (int i = 0; i < num_kids; i++) {
int kid = kids[node][i];
// Can we pair this node with this kid?
// Requirements:
// 1. Kid must be alone (available to pair with parent)
// 2. All other kids must be paired in their subtrees
if (alone[kid] && before[i] && after[i + 1]) {
paired[node] = 1;
break; // Found a valid pairing!
}
}
}
}
// ============================================================
// Output the answer
// ============================================================
// For each node i, the answer is whether its subtree can be paired
// Since node i is the ROOT of its subtree, we use paired[i]
// (The root cannot be paired upward to a parent)
string result(n, '0');
for (int i = 0; i < n; i++) {
result[i] = paired[i] ? '1' : '0';
}
cout << result << "\n";
return 0;
}