题解
用并查集
一开始把每个部落的第一人当作头头
在输入的时候
如果B部落发现 人a已经有头头A了 就让人a的头头A 的头头变为B
也就是 a->A->B
但如果a就是B的话 让a的头头是a 即他本身(否者会死循环 a的是A A的是a)
更新一下(新的在下面)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//dp里放的是每个人的祖先
vector<int> dp(10005);
int find(int x)
{
return dp[x] == x ? dp[x] : dp[x] = find(dp[x]);
}
int main()
{
int n;
cin >> n;
//一开始都弄成-1
fill(dp.begin(), dp.end(), -1);
int ans = n, ren = 0;
//让 部落的第一个人是 主子
int f;
int m;
for (int i = 1; i <= n; ++i)
{
cin >> m;
for (int p = 0; p < m; p++)
{
int x;
cin >> x;
if (p == 0)
f = x;
//之前有
if (dp[x] != -1)
{
//部落数
ans--;
//找出x原来的主子
int t = find(x);
//让x的主子 成为f的下属
dp[t] = f;
if (x == f)
{
dp[x] = x;
}
}
else
{
//人数加
ren++;
dp[x] = f;
}
}
}
cout << ren << " " << ans << endl;
cin >> m;
while (m--)
{
int a, b;
cin >> a >> b;
if (find(a) == find(b))
{
cout << "Y" << endl;
}
else
cout << "N" << endl;
}
return 0;
}
新
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <set>
using namespace std;
//存祖先
vector<int> dp(10005);
//部落数
int cnt = 0;
//查
int find(int x)
{
return dp[x] == x ? x : dp[x] = find(dp[x]);
}
//并
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y)
return;
--cnt;
dp[x] = y;
}
int main()
{
//默认祖先
iota(dp.begin(), dp.end(), 0);
//方便找一共多少人
set<int> people;
int N;
cin >> N;
while (N--)
{
int k, a;
//先把第一个人a 记录一下
//接下来通过人a 来把大家串起来
cin >> k >> a;
people.insert(a);
while (--k)
{
int x;
cin >> x;
people.insert(x);
//并
unite(a, x);
}
}
//—————————总人数-并起来的数量 就是没并在一起的人是数量 也就是部落数了
cout << people.size() << ' ' << people.size() + cnt << endl;
int Q;
cin >> Q;
while (Q--)
{
int x, y;
cin >> x >> y;
cout << ((find(x) == find(y)) ? "Y\n" : "N\n");
}
return 0;
}