题目大意

  有一个两部各有 \(n\) 个节点的二分图 \(G\),定义 \(G^m\) 为一个 \(m+1\) 层的图,每层有 \(n\) 个节点,相邻两层的诱导子图都和 \(G\) 相同。

  给你 \(m\),求对于所有 \(1\leq i\leq m\),\(G^i\) 的最小生成树的边权和。

  保证图连通。

  \(n,m\leq 100000,\text{边数 }\leq 200000,\text{边权}\leq 30\)

题解

  对于 \(G^i\),先求出用了多少种边权 \(<j\) 的边,再求出用了多少条边权 \(\leq j\) 的边,就可以得到用了多少条边权为 \(j\) 的边。

  那么边权就可以忽略了。

  现在要求出 \(G^i\) 有多少条边。

  从左往右扫,用并查集维护最后两层节点的连通性。

  那么再下一层的并查集肯定会是这两层的并查集加上一点边。

  当我们处理完一层的时候,求出这层新加的边对下一层的贡献。

  这层每加一条边,下一层就要在这两个集合右侧的点之间连边。

  然后不停地往右边传就好了。

  每加一条边就会合并两个集合,所以总共会加 \(O(n)\) 条边。

  时间复杂度:\(O(w(n+m+e)\alpha(n))\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=200010;
int f[N];
vector<pii> g[40],a,b;
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int c[N];
int merge(int x,int y)
{
if(find(x)==find(y))
return 0;
if(!c[find(y)])
c[find(y)]=c[find(x)];
f[find(x)]=find(y);
return 1;
}
int n,m,e;
ll ans[N];
ll s[N];
ll d[N];
int main()
{
open("c");
scanf("%d%d%d",&n,&m,&e);
int x,y,w;
for(int i=1;i<=e;i++)
{
scanf("%d%d%d",&x,&y,&w);
g[w].push_back(pii(x,y));
}
for(int i=1;i<=30;i++)
{
a.clear();
for(int j=1;j<=i;j++)
for(auto v:g[j])
a.push_back(v);
for(int j=1;j<=2*n;j++)
f[j]=j;
for(int j=1;j<=m;j++)
d[j]=0;
for(int j=1;j<=2*n;j++)
c[j]=0;
for(auto v:a)
d[1]+=merge(v.first,v.second+n);
b.clear();
for(int j=n+1;j<=2*n;j++)
if(!c[find(j)])
c[find(j)]=j;
else
b.push_back(pii(c[find(j)]-n,j-n));
for(int j=2;j<=m;j++)
{
a=b;
b.clear();
for(auto v:a)
if(find(v.first)!=find(v.second))
{
if(c[find(v.first)]&&c[find(v.second)])
b.push_back(pii(c[find(v.first)]-n,c[find(v.second)]-n));
merge(v.first,v.second);
}
else
d[j]--;
}
for(int j=2;j<=m;j++)
d[j]+=d[j-1];
for(int j=2;j<=m;j++)
d[j]+=d[j-1];
for(int j=1;j<=m;j++)
{
ans[j]+=i*(d[j]-s[j]);
s[j]=d[j];
}
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}

【XSY3345】生成树 并查集的更多相关文章

  1. HDU 4786 生成树 并查集+极大极小值 黑白边 确定选择白边的数量

    题意: 给定一个无向图 n 个点 m条无向边 u v val val == 1 表示边(u, v) 为白边 问能否找到n个点的生成树, 使得白边数为斐波那契数 思路: 并查集求图是否连通( 是否存在生 ...

  2. BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]

    题意: 一张图0,1两种边,构造一个恰有k条0边的生成树 优先选择1边构造生成树,看看0边是否小于k 然后保留这些0边,补齐k条,再加1边一定能构成生成树 类似kruskal的证明 #include ...

  3. hdu 1272 判断所给的图是不是生成树 (并查集)

    判断所给的图是不是生成树,如果有环就不是,如果没环但连通分量大于1也不是 find函数 用递归写的话 会无限栈溢出 Orz要加上那一串 手动扩栈 Sample Input6 8 5 3 5 2 6 4 ...

  4. 离线+生成树+并查集——cf1213G

    #include<bits/stdc++.h> using namespace std; #define N 200005 #define ll long long struct Edge ...

  5. 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

    图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...

  6. UVA 1395 苗条的生成树(最小生成树+并查集)

    苗条的生成树 紫书P358 这题最后坑了我20分钟,怎么想都对了啊,为什么就wa了呢,最后才发现,是并查集的编号搞错了. 题目编号从1开始,我并查集编号从0开始 = = 图论这种题真的要记住啊!!题目 ...

  7. 利用并查集求最大生成树和最小生成树(nlogn)

    hdu1233 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  8. Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)

    3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...

  9. 货车运输-洛谷-1967-LCA+最大生成树(kruskal(并查集))

    传送门 一道:LCA+最大生成树 个人认为把这两个的板子写好(并熟练掌握了之后)就没什么难的 (但我还是de了好久bug)qwq 最大生成树:其实就是最小生成树的变形 我用的是kruskal (个人觉 ...

随机推荐

  1. [JavaScript] requireJS基本使用

    requireJS 是一个 AMD 规范的模块加载器主要解决的js开发的4个问题1. 异步加载,防止阻塞页面渲染2. 解决js文件之间的依赖关系和保证js的加载顺序3. 按需加载 来实现一个 requ ...

  2. Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

    简介 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案.JSON Web Token 入门教程 - 阮一峰,这篇文章可以帮你了解JWT的概念.本文重点讲解Spring Boo ...

  3. js常用JSON数据操作

    JSON字符串: var  str = '{"name": "jack", "age": 13}'; JSON对象: var obj = { ...

  4. Servlet常用的接口和类

    使用接口和类的作用:Servlet也是依靠继承父类和实现接口来实现的.使用Servlet必须要引入两个包:javax.servlet和javax.servlet.http.所有的Servlet应用都是 ...

  5. 剑指前端(前端入门笔记系列)—— JS基本数据类型及其类型转换

    基本数据类型 ECMAScript中有5中简单数据类型性(也称为基本数据类型):Undefined.Null.Boolean.Number和String,还有一种复杂数据类型——Object,Obje ...

  6. CSS的使用方法

    参考资料:http://css.cuishifeng.cn/ 一.CSS的四种引入方式 1.行内式 行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐使用(与链接式 ...

  7. jsp:set/getProperty底层实现的探究

    关于jsp:set/getProperty底层实现的探究 今天上课讲到<jsp:useBean>时涉及到了<jsp:setProperty>和<jsp:getProper ...

  8. Centos7 使用 kubeadm 安装Kubernetes 1.13.3

    目录 目录 什么是Kubeadm? 什么是容器存储接口(CSI)? 什么是CoreDNS? 1.环境准备 1.1.网络配置 1.2.更改 hostname 1.3.配置 SSH 免密码登录登录 1.4 ...

  9. 20年硅谷技术牛人到访DataPipeline谈:技术如何与业务平衡发展

    导读:技术人员的常态是“左手支持业务签单,右手提升系统性能”,却经常陷入技术和业务该如何平衡发展的困惑?今天,且听一位硅谷牛人分享他的平衡之道. 以个人名誉申请31个国内外技术和产品专利,中国最佳CT ...

  10. ZOJ 2480 - Simplest Task in Windows

    Simplest Task in Windows Time Limit: 2 Seconds      Memory Limit: 65536 KB A typical windows platfor ...