ACM : Travel-并查集-最小生成树 + 离线-解题报告

Travel

Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u

/*题意
给出n【节点数】,m【连线数】,q【查询次数】;
输入m组数据  u【起点】,v【终点】,cost【权值】; (u,v)和 (v,u)表示两种不同的连线
输入q组查询数据;

要求
输出在m组数据中所有cost<q的所有节点连线的连线方式个数。  

注意:每个拥有n个节点的联通块有 n*(n-1)个联通分量 (连线数);
      每次两个联通块相连总连线数应该是(n1+n2)*(n1+n2-1);
      用一个数据来记录的话更新方式应该为 n-n1*(n1-1)-n2*(n2-1)+(n1+n2)*(n1+n2-1);
*/ 

//如果每一次都重新建立并查集,查询数q比较大的话肯定会超时的,看了别人博客说用离线思维;稍稍了解了一下啥叫离线思维。

//本题用离线思想,将查询按照X的大小升序排序,后面的查询就在前一步往后进行,复杂度减小很多

/*
神测试数据。。。。。【 T。T 】
1
5 5 12
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6333
6334
6335
12345
12381
12385
13000
233
5777
21726
21727
21725

*/

//AC代码:
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"algorithm"
using namespace std;
const int MX=2222222;
long long ans[MX];
int P[MX], num[MX];

struct node {
	int u, v, cost;
} side[MX];

bool cmp_side(node a,node b) {
	return a.cost < b.cost;
}

struct Que {
	int id, x; //id 记录输入时候的顺序 x记录查询值
} Q[MX];

bool cmp_que(Que a,Que b) {
	return a.x<b.x;
}

int find(int x) {
	return P[x]==x?x:(P[x]=find(P[x]));
}

int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		int n, m, q;
		scanf("%d%d%d", &n, &m, &q);
		for(int i=1; i<=n; i++) {
			P[i]=i;
			num[i]=1;       //初始化连通分量
		}
		for(int i=1; i<=m; i++) {	//把无向边加入队列
			scanf("%d%d%d", &side[i].u, &side[i].v, &side[i].cost);
		}
		sort(side+1,side+m+1,cmp_side);//升序排序无向边
		for(int i=1; i<=q; i++) {	//添加查询队列
			Q[i].id=i;
			scanf("%d",&Q[i].x);
		}
		sort(Q+1,Q+q+1,cmp_que);		//按照查询复杂度排序答案。
		int k=1;
		long long s=0;
		for(int i=1; i<=m; i++) {
			while(k<=q&&side[i].cost>Q[k].x)ans[Q[k++].id]=s; //把答案按照ID的顺序保存到ans数组中
			int rt1=find(side[i].u),rt2=find(side[i].v);
			if(rt1!=rt2) {
				long long n1=num[rt1],n2=num[rt2];
				//每个拥有n个节点的联通块有 n*(n-1)个联通分量 (对点)
				s=s-n1*(n1-1)-n2 *(n2-1)+(n1+n2)*(n1+n2-1);//去掉两个根的联通量在加上总和的联通分量
				P[rt1]=rt2;
				num[rt2]+=num[rt1];//加上节点的数量
			}
		}
		//ans[Q[k].id]=s; // 【这里居然看在上面读入ans之后还没有到最后一个,后面再测试数据才发现了这个问题。。。】
		while(k<=q)
			ans[Q[k++].id]=s;
		for(int i=1; i<=q; i++)
			printf("%I64d\n",ans[i]); //按照离线保存的实际查询顺序输出
	}
	return 0;
}

  

 
时间: 2024-08-25 09:22:22

ACM : Travel-并查集-最小生成树 + 离线-解题报告的相关文章

08年acm区域赛北京赛区 部分题解题报告

08年区域赛北京赛区 http://poj.org/searchproblem?field=source&key=Beijing+2008 POJ 3921 Destroying the bus stations 题目还是比较难的,当时的榜似乎只有4/25的通过/提交,其实题目数据很水.学长转换模型写了网络流求最小割,可以AC,不过自己造了个数据推翻了正确性.我写了个很挫的bfs套bfs,外层是最小的删除点数,内层是求最短路,数据很水可以AC.但比较蛋疼的在于bfs耗内存,而且队列中的点数是阶乘

ACM: 继续畅通工程-并查集-最小生成树-解题报告

继续畅通工程 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status Description 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态.现请你编写程序,计算出全省畅通需要的最低成本. Input 测试输入包含若干测试用例

ACM: The Suspects-并查集-解题报告

The Suspects Time Limit:1000MS Memory Limit:20000KB 64bit IO Format:%lld & %llu Description 严重急性呼吸系统综合症( SARS), 一种原因不明的非典型性肺炎,从2003年3月中旬开始被认为是全球威胁.为了减少传播给别人的机会, 最好的策略是隔离可能的患者. 在Not-Spreading-Your-Sickness大学( NSYSU), 有许多学生团体.同一组的学生经常彼此相通,一个学生可以同时加入几个小

hdu 1863 畅通工程 (并查集+最小生成树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863 畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 17593    Accepted Submission(s): 7417 Problem Description 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交

hdu 1272 小希的迷宫(并查集 最小生成树)

http://acm.hdu.edu.cn/showproblem.php?pid=1272 这题要求任意两个房间都相通又不能有环 即通过并查集求出是否构成最小生成树 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 100000 int fa[maxn+10]; int num[maxn+10

HDU 5441 Travel 并查集

HDU 5441 Travel 题意:一张无向图,q个查询,对于每个x,有多少对点之间的路径中最长的一条路不大于x. 思路:比赛时王秋平写的,我补下题.这题也比较简单,将边排序,从小到大加到并查集,对查询也排序,从小到大对于每个查询把不大于x的边加到并查集,用cnt[y]记录以y为根的连通块有多少节点,那么在连通块发生 变化时,ans=2 * cnt[x] * cnt[y] 1 #include <iostream> 2 #include <cstdio> 3 #include &

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构.我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论. Kruskal算法的过程: (1) 将全部边按照权值由小到大排序. (2) 按顺序(边权由小到大的顺序)考虑每条边,只要这条边和我们已经选择的边不构成圈,就保留这条边,否则放弃这条边. 算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通. 以下图为例: 边排

CodeForces - 891C: Envy(可撤销的并查集&amp;最小生成树)

For a connected undirected weighted graph G, MST (minimum spanning tree) is a subgraph of G that contains all of G's vertices, is a tree, and sum of its edges is minimum possible. You are given a graph G. If you run a MST algorithm on graph it would

1863 畅通工程-并查集最小生成树

题目链接 问题描述: 简单的最小生成树的题,将路径按cost从小到大排序,利用克鲁斯塔尔求最小生成树算法就行. 代码: 1 #include<iostream> 2 #include<queue> 3 #include<algorithm> 4 5 using namespace std; 6 struct Road 7 { 8 int beg; 9 int end; 10 int cost; 11 Road(int beg, int end, int cost) 12