Tyvj 1391 走廊泼水节

来源:互联网 发布:eplan软件使用心得 编辑:程序博客网 时间:2024/05/16 23:47

题目大意:
给定一个完全图唯一最小生成树,求这个完全图最小的边权和
完全图:结点两两之间都有边的图

首先我第一回做的时候写了个map骗分的做法。。。我以为N2logN可以过40%数据的,然而被多组数据卡时间了Orz
但!是!map仍然是一个高速骗分利器
所以我先总结下map的用法
map是一类容器,他可以做到哈希表能做的事,其内部由红黑树实现,因此效率十分高。
然后map是拿来做映射的,比如说我想要判断一个坐标(x,y)是否存在过,那我可以map<pair<int, int>, bool> id
第一个参数是索引,第二个参数是实际值,我每次if(id[make_pair(a,b)])
就可以判重
而且他那个id[]里什么都能放,你甚至可以放一个动态数组或者字符串进去。
还有一种我特别喜欢的用法,就是类似哈希的挂链
我们可以map<int, vector<int> > id注意,这里最右边一定要写成> >(带空格),不然编译器会识别为“>>”
想要遍历vector数组,需要建立一个迭代器
vector<int> :: iterator it
遍历则是for(it=id[x].begin(); it<id[x].end(); it++)
.end()返回的是最后一个元素的后一个位置的指针
注意 这里it是指针,需要*it来求值

正解

我们需要高速确定点对之间是否有边以及点对之间新建边的最小权值
可以把输入给的边来一次kruskal的过程,按权值排序,忽视之前的所有边,用并查集连接两个集合。
设想我们有两个点集合,x和y,两个集合之间因为一条边权为w的边要合并了
这里写图片描述
我们把x集合的每个点和y集合的所有点连边,就是一个完全图了,现在需要考虑那些边的边权。
由于我们是按照边权排序的,w此时一定为图中最大边,而题目要求为了最小生成树,也就是说我们新加入的边不能成为最小生成树的一部分,他不能比图中任何边小,这条边的权值又需要为整数,那自然就是w+1,我们此时就增加了(xy1)(w+1)边权

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <map>const int MAXN = 20010;using namespace std;int fa[MAXN],node[MAXN],rk[MAXN];#define debug(x) cerr << #x << "=" << x << endl;int tot,last[MAXN],depth[MAXN];long long total;long long ans, answ;int vis[MAXN],n,t;struct Edge{    int u,v,w,to;    Edge(){}    Edge(int u, int v, int w, int to) : u(u), v(v), w(w), to(to) {}}e[MAXN*2];inline void add(int u, int v, int w) {    e[++tot] = Edge(u,v,w,last[u]);    last[u] = tot;}void init() {    memset(last,0,sizeof(last));    tot = 0;    ans = 0;    answ = 0;    total = 0;    memset(e,0,sizeof(e));    memset(depth,0,sizeof(depth));    memset(vis,0,sizeof(vis));    memset(fa,0,sizeof(fa));    memset(rk,0,sizeof(rk));    memset(node,0,sizeof(node));}bool cmp(Edge a, Edge b) {    return a.w < b.w;}int find(int x) {    return fa[x] == x ? x : fa[x] = find(fa[x]);}bool jud(int a, int b) {    return find(a) == find(b);}void merge(int a,int b) {    node[find(b)] += node[find(a)];    fa[find(a)] = find(b);}int main() {    scanf("%d",&t);    while(t--) {        init();        scanf("%d", &n);        for(int i=1; i<n; i++) {            int u,v,w;            scanf("%d %d %d",&u,&v,&w);            total += w;            add(u,v,w);            add(v,u,w);        }        for(int i=1; i<=n; i++) {            fa[i] = i;            rk[i] = 1;            node[i] = 1;        }        sort(e+1,e+tot+1,cmp);        for(int i=1; i<=tot; i++) {            int u = e[i].u;            int v = e[i].v;            if(!jud(u,v)) {                ans += (long long)(e[i].w+1)*((long long)(node[find(u)])*(node[find(v)]) - 1);                merge(u,v);            }        }        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击