【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控件库(DSControls)中,DS按钮的功能非常多,通过设置不同的属性值来使按钮呈现不同的效果.DS按钮的常用属性如下: 使用不同的属性调出不同的外观样式示例
- AI产品的商业模式
AI产品的商业模式 ------------------------------------------------------------------------------------------ ...
- SpringBoot打包项目成war包,并部署到服务器的tomcat上
最近遇到项目需要上线部署到服务器,需要讲自己的SpringBoot项目打包成war包,部署到tomcat上. 下面记录下打包部署的过程. (1) 将SpringBoot项目打包成war包, 一.修改打 ...
- Java基础-异常、断言
处理错误 如果Java程序运行期间出现了错误,并且由于出现错误导致某些操作没有完成,程序应该能够返回到一种安全状态,并能够让用户执行一些其他的命令:或者允许用户保存所有操作结果,并以妥善的方式终止程序 ...
- SpringIOC/DI(2)
2019-03-08/09:24:37 开发环境:IDEA 1.创建Spring项目 File--New--project--Spring--Creat empty Spring-config.xml ...
- Jetty 开发指南: 嵌入式开发之HelloWorld
Jetty 嵌入式之 HelloWorld 本节提供一个教程,演示如何快速开发针对Jetty API的嵌入式代码. 1. 下载 Jar 包 Jetty被分解为许多jar和依赖项,通过选择最小的jar集 ...
- react native中一次错误排查 Error:Error: Duplicate resources
最近一直在使用react native中,遇到了很多的坑,同时也学习到了一些移动端的开发经验. 今天在做一个打包的测试时,遇到了一个问题,打包过程中报错“Error:Error: Duplicate ...
- 关于C++11右值引用和移动语义的探究
关于C++11右值引用和移动语义的探究
- IDEA启动tomcat乱码
1.找到IDEA安装目录 2.找到2个文件 3.编辑,在最后一行加入 -Dfile.encoding=UTF-8 4.修改IDEA里tomcat内得编码 5.修改IDEA中tomcat中,startu ...
- HTML基础-------HTML标签(2)
HTML标签(2) a标签(容器级单标签) 语义:跳转到指定的连接 属性 列表系列 1.无序列表 该列表由两部分组成:ul标签嵌套li标签(ul标签是典型的容器级标签) 图示: 2.有序列表 该列表由 ...