Explanation

Since the relation of friends is transitive, we can keep sets in which all the people in a set are friends. For each of these sets of friends, there will also be a set of enemies made up of the union of all the enemies of each person in the set of friends. Every person in this set of enemies will be an enemy of every person in the set of friends. To see why this is true, consider a person aa in the set of friends FF. Their enemy is bb in the set of enemies EE. Since an enemy of a friend is also an enemy, bb will be the enemy of all of aa's friends, which are the other people FF. Furthermore, each person in EE is friends with all other people in EE, since they share a common enemy aa.

To represent this, sets 0n10 \dots n - 1 in the code will be sets of friends, while each set ii in sets n2n1n \dots 2n - 1 will be be the enemies of set ini - n.

For each query, we let the two people be xx and yy and the root of xx's friends, yy's friends, xx's enemies and yy's enemies be xroot\texttt{xroot}, yroot\texttt{yroot}, exroot\texttt{exroot} and eyroot\texttt{eyroot}, respectively.

areEnemies

If any of xx's friends are friends with any of yy's enemies, then xx will be friends with one of yy's enemies. Thus, xx and yy will be enemies. To check if this is the case, we check if xroot\texttt{xroot} is the same as eyroot\texttt{eyroot} (which means that xx's friends are yy's enemies), or if yroot\texttt{yroot} is the same as exroot\texttt{exroot} (which means that yy's friends are xx's enemies).

areFriends

If xx and yy are in the same set, then they are friends.

setEnemies

When setting two people as enemies, we need to check if they are friends. We can use the areFriends\texttt{areFriends} function to do this. If they are not friends, we join xroot\texttt{xroot}'s set with eyroot\texttt{eyroot}'s set and join yroot\texttt{yroot}'s set with exroot\texttt{exroot}'s set, since the friend of an enemy is also an enemy.

setFriends

If we want to set two people as friends, we first need to check if they are enemies, using the areEnemies\texttt{areEnemies} function. If they are not enemies, we can join xroot\texttt{xroot}'s and yroot\texttt{yroot}'s sets. The enemies of two sets of friends will also become friends, so we also join exroot\texttt{exroot}'s and eyroot\texttt{eyroot}'s sets.

Implementation

Time Complexity: O(Qα(n))\mathcal{O}(Q \cdot \alpha(n)), where QQ is the number of operations

C++

#include <algorithm>
#include <iostream>
using namespace std;
int size[20000], parent[20000];
void init(int n) {
for (int i = 0; i < 2 * n; i++) {
parent[i] = i;
size[i] = 1;
}

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!