【XSY3345】生成树 并查集
题目大意
有一个两部各有 \(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】生成树 并查集的更多相关文章
- HDU 4786 生成树 并查集+极大极小值 黑白边 确定选择白边的数量
题意: 给定一个无向图 n 个点 m条无向边 u v val val == 1 表示边(u, v) 为白边 问能否找到n个点的生成树, 使得白边数为斐波那契数 思路: 并查集求图是否连通( 是否存在生 ...
- BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]
题意: 一张图0,1两种边,构造一个恰有k条0边的生成树 优先选择1边构造生成树,看看0边是否小于k 然后保留这些0边,补齐k条,再加1边一定能构成生成树 类似kruskal的证明 #include ...
- hdu 1272 判断所给的图是不是生成树 (并查集)
判断所给的图是不是生成树,如果有环就不是,如果没环但连通分量大于1也不是 find函数 用递归写的话 会无限栈溢出 Orz要加上那一串 手动扩栈 Sample Input6 8 5 3 5 2 6 4 ...
- 离线+生成树+并查集——cf1213G
#include<bits/stdc++.h> using namespace std; #define N 200005 #define ll long long struct Edge ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- UVA 1395 苗条的生成树(最小生成树+并查集)
苗条的生成树 紫书P358 这题最后坑了我20分钟,怎么想都对了啊,为什么就wa了呢,最后才发现,是并查集的编号搞错了. 题目编号从1开始,我并查集编号从0开始 = = 图论这种题真的要记住啊!!题目 ...
- 利用并查集求最大生成树和最小生成树(nlogn)
hdu1233 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...
- 货车运输-洛谷-1967-LCA+最大生成树(kruskal(并查集))
传送门 一道:LCA+最大生成树 个人认为把这两个的板子写好(并熟练掌握了之后)就没什么难的 (但我还是de了好久bug)qwq 最大生成树:其实就是最小生成树的变形 我用的是kruskal (个人觉 ...
随机推荐
- DS控件库 DS标签的另类用法之折叠展开
某些场合下,可以通过动态设置DS标签的文本内容来输出不同的显示效果,以下是示例. 示例中的素材 示例资源文本 String1="<linkimg=E1><b>&l ...
- [PHP] MIME邮件协议的multipart类型
邮件协议中的三种情况,对应下面的三种类型 multipart/mixed可以包含附件.multipart/related可以包含内嵌资源.multipart/alternative 纯文本与超文本共存 ...
- [TCP/IP] 计算机网络性能指标
速率:连接在计算机网络上的主机在数字信道上传输数据位数的速率单位是 b/s kb/s mb/s gb/s带宽:数字信道所能传输的最高数据率 查看我的网卡是144Mbps吞吐量:单位时间内通过某个网络的 ...
- jsp内置对象-response对象
一.概念 隐含对象response是javax.servlet.HttpServletResponse接口实现类的对象.response对象封装了JSP产生的响应,用于响应客户端的请求,向客户端输出信 ...
- 【土旦】 使用Vant 的Uploader 上传图片 重定义返回格式 使用FormData格式提交
前言 开发一个图片上传功能 需求要用vant中的Uploader , 发现 Uploader组件官方封装返回的数据是加密的,不适合我这个项目(需要上传到本地ftp服务器), 看了一下官方 issue ...
- PHP的简单跳转提示的实现
在PHP开发中,尤其是MVC框架或者项目中,会碰到很多跳转情况,比如:登录成功或失败后的跳转等等. 以下以MVC框架开发中为基础,示例讲解: 在基础控制器类中:Conrtoller.class.php ...
- 第四次上机,ASP组件的使用
<html> <body> <% '以下连接数据库,建立一个Connection对象实例conn Set conn=Server.CreateObject("A ...
- C++ 子类继承父类纯虚函数、虚函数和普通函数的区别
C++三大特性:封装.继承.多态,今天给大家好好说说继承的奥妙 1.虚函数: C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现.子类可以重写父类的虚函数实现子类 ...
- 【Linux】【MySQL】CentOS7安装最新版MySQL8.0.13(最新版MySQL从安装到运行)
1.前言 框框博客在线报时:2018-11-07 19:31:06 当前MySQL最新版本:8.0.13 (听说比5.7快2倍) 官方之前表示:MySQL 8.0 正式版 8.0.11 已发布,MyS ...
- idea中Springcloud同时运行多个模块、微服务
idea中有个窗口叫做 Run DashBoard 在这里可以管理多个模块的启停,这个面板一般情况下是关闭的打开Run DashBoard面板 在工程的.idea中找到workspace.xml,并找 ...