The 15th Chinese Northeast Collegiate Programming Contest K.City

目录

题目:

思路:​​​​​​​

代码:


题目:


原题:

         Lucida occupies n cities connected by m undirected roads, and each road has a strength ki. The enemy will attack to destroy these roads. When the enemy launches an attack with damage x, all roads with strength less than x will be destroyed.

        Now Lucida has Q questions to ask you, how many pairs of cities are reachable to each other if the enemy launches an attack with damage pi. City x and city y are reachable, which means that there is a path from x to y, and every road's strength in that path is greater than or equal to pi.

简述:

        给定两两城市之间的道路长度和一系列伤害值。强度大于等于伤害值的道路不会被破坏。问对于每一个伤害值,有多少对可以互相到达的城市。

思路:


存储:用结构体存道路的起始和权值,以及询问的伤害和序号。重载分别按权值和伤害降序排序。

算法:并查集,维护集合大小。

操作:

        将道路按权值降序排序(为了先连接可连接的城市),询问按伤害降序排序(伤害小的集合大小可以在伤害大的集合基础上累加)。对于每一个伤害值,累加新连通的两个集合的城市数,将可合并且未合并的集合合并,并更新集合大小。

代码:

#include
#include
#include
using namespace std;

typedef long long ll;
const int N = 2e5 + 5;
int p[N];      //记祖先和集合的大小
ll size[N], ans[N];

struct node {
	int x, y, k;
	bool operator < (const node &rd)const {  //按路的权值降序(先搭能搭的)
		return k > rd.k;
	}
} road[N];

struct query {
	int id, p;
	bool operator < (const query &qy)const {  //按伤害的值降序(先搭条件严苛的)
		return p > qy.p;
	}
} q[N];

int find(int x) {							  //并查集
	return x == p[x] ? x : find(p[x]);
}

int main() {

	int T;
	cin >> T;

	while (T --) {
		int n, m, Q;
		cin >> n >> m >> Q;

		memset(ans, 0, sizeof ans);

		for (int i = 1; i <= n ; ++ i) {  //初始化
			p[i] = i;
			size[i] = 1;
		}

		for (int i = 0; i < m; ++ i) {
			int x, y, k;
			cin >> x >> y >> k;
			road[i] = {x, y, k};
		}

		for (int i = 0; i < Q; ++ i) {
			cin >> q[i].p;
			q[i].id = i;
		}

		sort(road, road + m);          //排序
		sort(q, q + Q);

		ll sum = 0;
		int j = 0;
		for (int i = 0;  i < Q; ++ i) {
			int damage = q[i].p;
			while (j < m && road[j].k >= damage) {  //能搭
				int u = find(road[j].x);
				int v = find(road[j].y);

				if (u != v) { //未搭
					sum += (ll)size[u] * size[v];  //为两个集合的城市搭桥
					p[u] = v;                      //合并顶点
					size[v] += size[u];            //合并大小
				}
				++ j;
			}
			ans[q[i].id] = sum;
		}
		for (int i = 0; i < Q; ++ i) cout << ans[i] << endl;
	}
	return 0;
}

你可能感兴趣的:(算法,数据结构,c++,并查集,codeforces)