题意:给出n个公司和他们各自的实力值。有两种操作:合并两个公司,形成联盟。查询一个公司对应联盟的实力值的总和。
思路:裸的并查集。注意一点,可能会对已经是同一个联盟的公司再次合并,所以在合并时,需要判断。数据用long long.
坑:1.long long 的范围是10^18,所以本题可以用。当时认为结果过大,所以高精度了,TLE到死啊!!!
2.公司标号是从1开始的,所以并查集的初始化要多一个元素。
代码:
#include <cstdio>
#include <vector>
using namespace std;
const int MAX = 100010;
long long d[MAX];
struct DisjointSet{
vector<int> rank, father;
DisjointSet(int n) : rank(n+1), father(n+1){
for (int i = 1; i <= n; ++i)
father[i] = i;
}
int find(int x){
return x = x == father[x] ? x : find(father[x]);
}
void merge(int x, int y){
x = find(x), y = find(y);
if (x != y){
if (rank[x] > rank[y]){
father[y] = x;
d[x] += d[y];
}
else{
father[x] = y;
d[y] += d[x];
if (rank[x] == rank[y])
rank[y]++;
}
}
}
};
int main(void)
{
int T;
scanf("%d", &T);
while (T--){
int n, m;
scanf("%d %d", &n, &m);
DisjointSet s(n);
for (int i = 1; i <= n; ++i)
scanf("%lld", &d[i]);
while (m--){
int choice;
scanf("%d", &choice);
if (choice == 1){
int x, y;
scanf("%d %d", &x, &y);
s.merge(x, y);
}
else{
int x;
scanf("%d", &x);
int y = s.find(x);
printf("%lld\n", d[y]);
}
}
}
return 0;
}