MuWu大喊:“江南老贼”
from CUP oj 学长自出题
时间限制:1s
内存限制:256MB
题目描述:
总所周知,这个世界上龙、混血种势不两立,MuWu是混血种的领袖,当尼德霍格苏醒时,他需要召集全世界的混血种去杀死它。
世界上共有n个混血种组织,第i个组织有a[i]个人,一共有m对组织会相互联系,然而有些组织间可能有些恩恩怨怨,他们之间并不会产生联系。若是两个互不联系的组织间可以通过一个中间组织产生联系,MuWu认为他们之间也可以产生联系。
现在MuWu有q个问题,每个问题下,他问出一个组织,他想知道这个组织最多能联系上多少人(包括自身)。
有k对仇怨不深的组织,对于第i对的两个组织x[i]和y[i],MuWu可以花v[i]元钱(混血种都得用RMB)使他们产生联系,MuWu需要花最少的钱使得所有组织都能联系上。
MuWu并不会这些问题,所以他想问下你,你能帮助他吗?
输入:
第一行有三个数n(1≤n≤1e5)和m(0≤m≤1e5),代表n个混血种组织,m个联系。
第二行n个数,第i个数代表a[i]。
后面跟着m行,每行有两个数x(1≤x≤n)和y(1≤y≤n),表示x和y会相互联系。
后面跟着一行,有一个数q(1≤q≤n),代表q个问题。
后面跟着q行,每行一个数,代表MuWu想问该组织可以联系上多少人。
后面跟着一行,有一个数k(1≤k≤1e5),代表k个仇恨不深的联系
后面跟着k行,每行有三个数x(1≤x≤n)和y(1≤y≤n)和v(0≤v≤1e4),表示x和y之间产生联系需要花v元钱。(题目保证最后一定能联系上所有人)
不保证无重边和自环。
输出:
前q行,每行代表一个问题下的答案
最后一行输出最少花多少钱使得所有人都能联系上
样例输入:
6 3
5 6 7 8 9 10
1 2
3 4
3 5
6
1
2
3
4
5
6
4
1 3 5
5 6 6
2 3 2
3 6 5
样例输出:
11
11
24
24
24
10
7
最开始的时候是每个部落都独立存在,然后m行,将一对部落所在集合合并,这里我们建一个数组a[]表示所能联系到的人数,每次合并就将合并过去的根节点的人数累加到合并后的根节点上,这样在后续的q组查询中都是只需要查找一下father就可以了。
经典并查集!
这个题目需要注意好几个地方都可以缩短路径,而且要使用cstdio才行!
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int father[100005];
int a[100005];
int find(int x) {
if(father[x] == x)
return x;
return father[x] = find(father[x]);
}
struct E {
int f, t, w;
}e[100005];
bool cmp(E a, E b) {
return a.w < b.w;
}
long long n, m, q, k, all;
int from, to, x, y;
int main() {
scanf("%d %d",&n,&m), all = n - 1;
for(int i = 1; i <= n; ++i) scanf("%d",&a[i]), father[i] = i;
for(int i = 1; i <= m; ++i) {
scanf("%d %d",&from,&to), x = find(from), y = find(to);
if(x != y)
father[x] = y, a[y] += a[x], --all;
}
scanf("%d",&q);
while(q--)
scanf("%d",&from), printf("%d\n", a[find(from)]);
scanf("%d",&k);
long long sum = 0;
for(int i = 1; i <= k; ++i)
scanf("%d %d %d",&e[i].f,&e[i].t,&e[i].w);
sort(e + 1, e + 1 + k, cmp);
for(int i = 1; all; ++i) {
x = find(e[i].f), y = find(e[i].t);
if(x != y) {
father[x] = y, sum += e[i].w, --all;
}
}
scanf("%d",&sum);
return 0;
}