并查集 - 2
>1 樱子的爱好
题目
https://codeforces.com/contest/2008/problem/D
思路
以
5 4 1 3 2
10011
为例
i = 1, p1 = 5, s5 = 1--> i = 5, p5 = 2, s2 = 0 --> i = 2, p2 = 4, s4 = 1 --> i = 4, p4 = 3, s3 = 0 --> i = 3, p3 = 1, s1 = 1
无论i = 1还是5, 2, 4, 3,最终黑色的个数都一样,因为会重复这个过程,所以它们就在一根树枝上,可以把1看作根结点,后面的数字标记一下,表示已经操作过了,就能跳过,将它们的父亲都设为1, 最终遍历就直接输出父亲节点的黑色数量
代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
vector<int> p(n+1, 0), a(n+1, 0), goal(n+1, 0), cnt(n+1, 0), nu(n+1, 0);
for (int i = 1; i <= n; i++) cin >> p[i], a[i] = p[i];
string s;
cin >> s;
for (int i = 0; i < n; i++)
{
if (s[i] == '0') nu[i + 1]++;
}
int count = 0;
for (int i = 1; i <= n; i++)
{
if (!goal[i])
{
int num = p[i];
cnt[i] += nu[num];
goal[num] = 1;
count++;
int res = p[num];
p[num] = i;
while (num != i)
{
num = res;
cnt[i] += nu[num];
goal[num] = 1;
count++;
res = p[num];
p[num] = i;
}
if (count == n) break;
}
}
for (int i = 1; i <= n; i++) cout << cnt[p[a[i]]] << ' ';
cout << endl;
}
}
>2 小诚因为金铲铲D不到牌破产啦
题目
http://oj.whpu.tech:7788/problem/299
代码
#include <iostream>
#include <string>
using namespace std;
const int N = 2e5 + 10;
int p[N], a[N], b[N];
int findd(int x);
void uniona(int x, int y);
int main()
{
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i], p[i] = i;
for (int i = 1; i <= n; i++) cin >> b[i];
while (m--)
{
int x, y; cin >> x >> y;
int p1 = findd(x), p2 = findd(y);
if (p1 != p2) uniona(p1, p2);
}
for (int i = 1; i <= n; i++)
{
if (i == p[i])
{
if (a[i] != b[i])
{
cout << "No" << endl;
return 0;
}
}
}
cout << "Yes" << endl;
}
int findd(int x)
{
int a = x;
while (a != p[a]) a = p[a];
int b = x;
while (b != a)
{
int c = p[b];
p[b] = a;
b = c;
}
return a;
}
void uniona(int x, int y)
{
p[x] = y;
a[y] += a[x];
b[y] += b[x];
}