NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并
思路:
Kruskal求最大生成树+倍增LCA
// by SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 105000
int n,m,tot=0,xx,yy,zz,ans;
int first[N],v[N*10],next[N*10],w[N*10],f[N],dep[N],fa[N][20],minn[N][20];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
struct EDGE{int from,to,weight;}Edge[50500];
void add(int x,int y,int z){
w[tot]=z,v[tot]=y;
next[tot]=first[x];
first[x]=tot++;
}
bool cmp(EDGE x,EDGE y){return x.weight>y.weight;}
void dfs(int x){
for(int j=1;j<=18;j++){
fa[x][j]=fa[fa[x][j-1]][j-1];
minn[x][j]=min(minn[x][j-1],minn[fa[x][j-1]][j-1]);
}
for(int i=first[x];~i;i=next[i])
if(dep[v[i]]==-1){
dep[v[i]]=dep[x]+1;
fa[v[i]][0]=x;minn[v[i]][0]=w[i];
dfs(v[i]);
}
}
int lca(int x,int y){
int ans=0x3fffffff;
if(dep[x]<dep[y])swap(x,y);
for(int i=18;i>=0;i--)if(dep[x]>=dep[y]+(1<<i))ans=min(ans,minn[x][i]),x=fa[x][i];
if(x==y)return ans;
for(int i=18;i>=0;i--)
if(fa[x][i]!=fa[y][i]){
ans=min(ans,min(minn[x][i],minn[y][i]));
x=fa[x][i];y=fa[y][i];
}
return min(ans,min(minn[x][0],minn[y][0]));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)f[i]=i;
memset(dep,-1,sizeof(dep));
memset(minn,0x3f,sizeof(minn));
memset(first,-1,sizeof(first));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&xx,&yy,&zz);
Edge[i].from=xx;Edge[i].to=yy;Edge[i].weight=zz;
}
sort(Edge+1,Edge+1+m,cmp);
for(int i=1;i<=m;i++)
if(find(Edge[i].from)!=find(Edge[i].to)){
f[find(Edge[i].from)]=find(Edge[i].to);
add(Edge[i].from,Edge[i].to,Edge[i].weight);
add(Edge[i].to,Edge[i].from,Edge[i].weight);
}
dep[find(1)]=0;dfs(find(1));
scanf("%d",&m);
while(m--){
scanf("%d%d",&xx,&yy);
if(~dep[xx]&&~dep[yy])printf("%d\n",lca(xx,yy));
else puts("-1");
}
}
队长讲了还有一中很奇怪的方法可以乱搞。
就是:Bling 并查集!
我们可以想到Kruskal进行的过程中是把两个连通块连起来,中间连的边一定比连通块里面的边要小。
那么我们可以考虑按秩合并。。可以证明这样树的高度是log的。
然后直接暴力求LCA即可
网上是这么说的:
启发式并查集,就是维护每个集合的深度,在合并两个集合的时候把小的那个集合挂在大集合下。
在此题中呢,求最大生成树的同时,不把新加入的一条边作为计算答案的树,而是把两个集合的祖先加入树中,边权就是原来边的两个边权。看到这,不禁产生了疑问,树的边权和形态与求出的最大生成树都不一样,为啥能做???其实没有关系,因为新加入的边不影响
原来集合中两点的答案,合并的两个集合中的点合并后肯定要经过原来这条边,那我把祖先接起来用原来边的边权也是一样的。
但是这么做,由于使用了启发式合并,那么最后新的树高度可以证明不会超过logn(其实我也不会证大笑),那么我们不用倍增处理这棵树,直接暴力求lca即可,不仅代码短,而且常数小!!!
// by SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 105000
int n,m,tot=0,xx,yy,zz;
int first[N],v[N*10],next[N*10],w[N*10],f[N],dep[N],fa[N],size[N],minn[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
struct EDGE{int from,to,weight;}Edge[50500];
void add(int x,int y,int z){w[tot]=z,v[tot]=y;next[tot]=first[x];first[x]=tot++;}
bool cmp(EDGE x,EDGE y){return x.weight>y.weight;}
void dfs(int x){
for(int i=first[x];~i;i=next[i])
if(dep[v[i]]==-1){
dep[v[i]]=dep[x]+1;
fa[v[i]]=x;minn[v[i]]=w[i];
dfs(v[i]);
}
}
void lca(int x,int y){
int ans=0x3fffffff;
if(dep[x]>dep[y])swap(x,y);
while(dep[x]!=dep[y])ans=min(minn[y],ans),y=fa[y];
while(x!=y){
ans=min(ans,min(minn[x],minn[y]));
x=fa[x];y=fa[y];
}
printf("%d\n",ans);
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)size[i]=1;
for(int i=1;i<=n;i++)f[i]=i;
memset(dep,-1,sizeof(dep));
memset(first,-1,sizeof(first));
memset(minn,0x3f,sizeof(minn));
for(int i=1;i<=m;i++){
scanf("%d%d%d",&xx,&yy,&zz);
Edge[i].from=xx;Edge[i].to=yy;Edge[i].weight=zz;
}
sort(Edge+1,Edge+1+m,cmp);
for(int i=1;i<=m;i++){
int fx=find(Edge[i].from),fy=find(Edge[i].to);
if(fx!=fy){
if(size[fx]>size[fy])swap(fx,fy);
f[fx]=fy;size[fy]+=fx;
add(fx,fy,Edge[i].weight);add(fy,fx,Edge[i].weight);
}
}
dep[find(1)]=0;dfs(find(1));
scanf("%d",&m);
while(m--){
scanf("%d%d",&xx,&yy);
if(~dep[xx]&&~dep[yy])lca(xx,yy);
else puts("-1");
}
}
NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并的更多相关文章
- 【bzoj4668】冷战 并查集按秩合并+朴素LCA
题目描述 1946 年 3 月 5 日,英国前首相温斯顿·丘吉尔在美国富尔顿发表“铁幕演说”,正式拉开了冷战序幕. 美国和苏联同为世界上的“超级大国”,为了争夺世界霸权,两国及其盟国展开了数十年的斗争 ...
- 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增
倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...
- NOIP2013 D1T3 货车运输
[NOIP2013T3]货车运输 背景 noip2013day1 描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重 量限制,简称限重.现在有 q 辆货 ...
- 洛谷P1967货车运输——倍增LCA
题目:https://www.luogu.org/problemnew/show/P1967 就是倍增LCA的裸题,注意一些细节即可. 代码如下: #include<iostream> # ...
- NOIP2013 D1T3 货车运输 zz耻辱记
目录 先来证明下lemma: 图上2点间最小边权最大的路径一定在MST上 感性理解下: 每次kruskal algo都连接最大的不成环边 此时有2个未联通的联通块被连起来. 那么考虑u, v两点的联通 ...
- xsy 2018 【NOIP2013】货车运输
[NOIP2013]货车运输 Description A 国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有q辆货车在运输货物,司机们想知道每辆车在不超 ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- LCA tarjan+并查集POJ1470
LCA tarjan+并查集POJ1470 https://www.cnblogs.com/JVxie/p/4854719.html 不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻 ...
- NOIP2013 货车运输 倍增
问题描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能 ...
随机推荐
- Deutsch lernen (14)
1. das Abseits, - 越位 Der Linienrichter winkte Abseits. winken - winkte - gewunken 示意 2. abs ...
- 时序分析:ARMA方法(平稳序列)
憔悴到了转述中文综述的时候了........ 在统计学角度来看,时间序列分析是统计学中的一个重要分支, 是基于随机过程理论和数理统计学的一种重要方法和应用研究领域. 时间序列按其统计特性可分为平稳性 ...
- C++对象的内存模型
1. 普通对象模型 对象是如何在内存中布局的? 成员 存放位置 访问范围 非静态数据成员 每一个对象体内 为该对象专有 静态数据成员 程序的静态存储区内,只有一份实体 为该类所有对象共享 成员函数(静 ...
- BZOJ 5466: [Noip2018]保卫王国 动态DP
Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...
- 爬取某网站景区列表并保存为csv文件
网址:http://www.halehuo.com/jingqu.html 经过查看可以发现,该景区页面没有分页,不停的往下拉,页面会进行刷新显示后面的景区信息 通过使用浏览器调试器,发现该网站使用的 ...
- 50.常用的query查询方式
主要知识点 match all match multi match range query term query terms query exist query 1.match all ...
- 4.Thymeleaf的常用标签
一.常用标签 二.foreach案例 1.创建项目 2. 创建Student.java package cn.kgc.pojo; /** * Created by Administrator on 2 ...
- 2.Git可视化操作
1.在本地新建版本库 首先,我们打开Git GUI是这样的一个界面,选择第一项,新建版本库. 然后选择你需要进行版本管理的项目路径,我选择了一个LoginDemo的项目. 当你创建了版本库的时候,你可 ...
- display显示属性理解
display属性设置一个元素应如何显示,是我们在前端开发中常常使用的一个属性,其中,最常见的有: 目录 display:none;表示此元素将不被显示. display:block;将元素显示为块元 ...
- dubbo-源码阅读之javaspi&javasist简单使用
dubbo可扩展的点的类的对象创建 都是用类似javaspi和javasist的思想来做的.所以看后面代码 先熟悉一下java的SPI和javasist的使用 如ServicesConfig的代码 p ...