// #include <bits/stdc++.h>
// using namespace std;
// #define MAX_HEIGHT 100000

// // Tree Node
// struct Node
// {
//    int data;
//    Node* left;
//    Node* right;
// };

// // Utility function to create a new Tree Node
// Node* newNode(int val)
// {
//    Node* temp = new Node;
//    temp->data = val;
//    temp->left = NULL;
//    temp->right = NULL;

//    return temp;
// }



// int leftLeavesSum(Node *root);

// // Function to Build Tree
// Node* buildTree(string str)
// {
//    // Corner Case
//    if(str.length() == 0 || str[0] == 'N')
//        return NULL;

//    // Creating vector of strings from input
//    // string after spliting by space
//    vector<string> ip;

//    istringstream iss(str);
//    for(string str; iss >> str; )
//        ip.push_back(str);

//    // Create the root of the tree
//    Node* root = newNode(stoi(ip[0]));

//    // Push the root to the queue
//    queue<Node*> queue;
//    queue.push(root);

//    // Starting from the second element
//    int i = 1;
//    while(!queue.empty() && i < ip.size()) {

//        // Get and remove the front of the queue
//        Node* currNode = queue.front();
//        queue.pop();

//        // Get the current node's value from the string
//        string currVal = ip[i];

//        // If the left child is not null
//        if(currVal != "N") {

//            // Create the left child for the current node
//            currNode->left = newNode(stoi(currVal));

//            // Push it to the queue
//            queue.push(currNode->left);
//        }

//        // For the right child
//        i++;
//        if(i >= ip.size())
//            break;
//        currVal = ip[i];

//        // If the right child is not null
//        if(currVal != "N") {

//            // Create the right child for the current node
//            currNode->right = newNode(stoi(currVal));

//            // Push it to the queue
//            queue.push(currNode->right);
//        }
//        i++;
//    }

//    return root;
// }

// void inorder(Node *root, vector<int> &v)
// {
//     if(root==NULL)
//         return;

//     inorder(root->left, v);
//     v.push_back(root->data);
//     inorder(root->right, v);
// }

// int main() {
//    freopen("input.txt","r", stdin);
//    freopen("output.txt","w", stdout);
//    int t;
//    string tc;
//    getline(cin, tc);
//    t=stoi(tc);
//    //cout << t << endl;
//    while(t--)
//    {
//         string s; 
//        getline(cin, s);
//        Node* root = buildTree(s);

//        getline(cin, s);
       
//         cout << leftLeavesSum(root) << endl;

//        cout<<"~"<<endl;
//    }
//    return 0;
// }


// bool isLeaf(Node *node) 
// { 
//    if (node == NULL) 
//        return false; 
//    if (node->left == NULL && node->right == NULL) 
//        return true; 
//    return false; 
// } 

// // This function returns sum of all left leaves in a given 
// // binary tree 
// int leftLeavesSum(Node *root) 
// { 
//     // Initialize result 
//     int res = 0; 
  
//     // Update result if root is not NULL 
//     if (root != NULL) 
//     { 
//        // If left of root is NULL, then add key of 
//        // left child 
//        if (isLeaf(root->left)) 
//             res += root->left->data; 
//        else // Else recur for left child of root 
//             res += leftLeavesSum(root->left); 
  
//        // Recur for right child of root and update res 
//        res += leftLeavesSum(root->right); 
//     } 
  
//     // return result 
//     return res; 
// } 







//--------------------------------------division----------------------------------------------------




















// #include<bits/stdc++.h>

// using namespace std;

// // Tree Node
// struct Node {
//     int data;
//     Node *left;
//     Node *right;

//     Node(int val) {
//         data = val;
//         left = right = NULL;
//     }
// };


// int getRandomFromRange(int l, int r) {
//     return (l + (rand() % (r - l + 1)));
// }

// // Return the string representing the BST
// // with n nodes where every node is from
// // the range [l, r]
// // Note that the number of integers in
// // the range [l, r] must be >= n
// string generateBST(int n, int l, int r) {
//     string str = "";

//     queue<pair<int, pair<int, int> > > queue;

//     // Create the root node
//     int root = getRandomFromRange(l, r);

//     // Add the root node and its
//     // range in the queues
//     queue.push({root, {l, r}});

//     str += (to_string(root) + " ");

//     // Number of nodes in the current tree
//     int valid = 1;

//     while (!queue.empty()) {

//         // Get the current node
//         pair<int, pair<int, int>> currNode = queue.front();
//         queue.pop();

//         // If the tree has been generated
//         if (valid >= n)
//             break;

//         // If the left node is not possible
//         if (currNode.first == currNode.second.first) {
//             str += "N ";
//         } else {

//             // Generate the left child
//             int leftChild = getRandomFromRange(currNode.second.first, currNode.first - 1);

//             // Add the left child and its range to the queue
//             queue.push({leftChild, {currNode.second.first, currNode.first - 1}});

//             str += (to_string(leftChild) + " ");
//             valid++;
//         }

//         // If the tree has been generated
//         if (valid >= n)
//             break;

//         // If the right node is not possible
//         if (currNode.first == currNode.second.second) {
//             str += "N ";
//         } else {

//             // Generate the right child
//             int rightChild = getRandomFromRange(currNode.first + 1, currNode.second.second);

//             // Add the left child and its range to the queue
//             queue.push({rightChild, {currNode.first + 1, currNode.second.second}});
//             str += (to_string(rightChild) + " ");
//             valid++;
//         }
//     }
//     return str;
// }

// // Return the string representing the binary tree with
// // n nodes where every node is from the range [l, r]
// string generalTreeDuplicates(int n, int l, int r, int factor) {
//     string str = "";

//     // To store the count of total nodes including
//     // null children of every valid node
//     int count = 2;

//     // To store the count of all valid nodes
//     int valid = 1;


//     // Generate the root node to the queue
//     int root = getRandomFromRange(l, r);
//     str += (to_string(root) + " ");

//     while (valid < n) {

//         // Time to hit null
//         if ((count % factor) == 0) {
//             str += "N ";
//         }

//             // Generate the left child
//         else {

//             // Get a random value for the left child
//             int leftChild = getRandomFromRange(l, r);
//             str += (to_string(leftChild) + " ");

//             // Increment the count of valid nodes
//             valid++;
//         }

//         // A node has been added
//         count++;

//         // If the tree has been generated
//         if (valid >= n)
//             break;

//         // Time to hit null
//         if ((count % factor) == 0) {
//             str += "N ";
//         }

//             // Generate the right child
//         else {

//             // Get a random value for the right child
//             int rightChild = getRandomFromRange(l, r);
//             str += (to_string(rightChild) + " ");

//             // Increment the count of valid nodes
//             valid++;
//         }

//         // Another node has been added
//         count++;
//     }
//     str += "\n";
//     return str;
// }

// Node *buildTree(string str) {
//     // Corner Case
//     if (str.length() == 0 || str[0] == 'N')
//         return NULL;

//     // Creating vector of strings from input
//     // string after spliting by space
//     vector<string> ip;

//     istringstream iss(str);
//     for (string str; iss >> str;)
//         ip.push_back(str);

//     // Create the root of the tree
//     Node *root = new Node(stoi(ip[0]));

//     // Push the root to the queue
//     queue<Node *> queue;
//     queue.push(root);

//     // Starting from the second element
//     int i = 1;
//     while (!queue.empty() && i < ip.size()) {

//         // Get and remove the front of the queue
//         Node *currNode = queue.front();
//         queue.pop();

//         // Get the current node's value from the string
//         string currVal = ip[i];

//         // If the left child is not null
//         if (currVal != "N") {

//             // Create the left child for the current node
//             currNode->left = new Node(stoi(currVal));

//             // Push it to the queue
//             queue.push(currNode->left);
//         }

//         // For the right child
//         i++;
//         if (i >= ip.size())
//             break;
//         currVal = ip[i];

//         // If the right child is not null
//         if (currVal != "N") {

//             // Create the right child for the current node
//             currNode->right = new Node(stoi(currVal));

//             // Push it to the queue
//             queue.push(currNode->right);
//         }
//         i++;
//     }

//     return root;
// }

// void storeNodesInOrder(Node *root, vector<Node *> &inOrder) {
//     if (!root)
//         return;

//     storeNodesInOrder(root->left, inOrder);
//     inOrder.push_back(root);
//     storeNodesInOrder(root->right, inOrder);
// }

// string toString(Node *root) {
//     if (root == nullptr)
//         return "N\n";

//     string str;
//     queue<Node *> qq;
//     qq.push(root);

//     while (!qq.empty()) {
//         Node *curr = qq.front();
//         qq.pop();

//         if (curr == nullptr) {
//             str += "N ";
//             continue;
//         }
//         str += (to_string(curr->data) + " ");
//         qq.push(curr->left);
//         qq.push(curr->right);
//     }
//     str += "\n";
//     return str;
// }




// const int N = 10000, MAXI = 100005;

// int main() {
//     freopen("output.txt", "r", stdin);
//     freopen("input.txt", "w", stdout);
//     srand(time(nullptr));
//     int tc = 10;
//     cout << tc << "\n";
//     while (tc--) {
//         int n = rand()%N+1;
//         int l = 1, r = MAXI;
//         int factor = 2 + rand() % 8;


//         auto treeString = generateBST(n, l, r);
//         Node *root = buildTree(treeString);

//         cout << treeString << endl;
        
        
//         cout << "~\n";
//     }

//     return 0;
// }








//---------------------------------------------//





/* while(!cin.eof()) */
 
#include<bits/stdc++.h>
using namespace std; 
#define int long long 
#define mod (int)(1e9)
#define endl '\n'
#define MAXI (int)(3e18+10)
#define N 200005



// Driver code to test above functions
int32_t main()
{
    
     
    ios_base::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);

    int n;
    cin >> n;
    int a[n+5];
    memset(a, 0, sizeof a);
    for(int i=2;i<=n;i++)
    {
        int x;
        cin >> x;
        a[x]++;
    }

    for(int i=1;i<=n;i++)
        cout << a[i] << endl;


    return 0;
}  


Measured memory_bytes: 5152