思路:

Kruskal求最大生成树+倍增LCA

  1. // by SiriusRen
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. #define N 105000
  7. int n,m,tot=0,xx,yy,zz,ans;
  8. int first[N],v[N*10],next[N*10],w[N*10],f[N],dep[N],fa[N][20],minn[N][20];
  9. int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
  10. struct EDGE{int from,to,weight;}Edge[50500];
  11. void add(int x,int y,int z){
  12. w[tot]=z,v[tot]=y;
  13. next[tot]=first[x];
  14. first[x]=tot++;
  15. }
  16. bool cmp(EDGE x,EDGE y){return x.weight>y.weight;}
  17. void dfs(int x){
  18. for(int j=1;j<=18;j++){
  19. fa[x][j]=fa[fa[x][j-1]][j-1];
  20. minn[x][j]=min(minn[x][j-1],minn[fa[x][j-1]][j-1]);
  21. }
  22. for(int i=first[x];~i;i=next[i])
  23. if(dep[v[i]]==-1){
  24. dep[v[i]]=dep[x]+1;
  25. fa[v[i]][0]=x;minn[v[i]][0]=w[i];
  26. dfs(v[i]);
  27. }
  28. }
  29. int lca(int x,int y){
  30. int ans=0x3fffffff;
  31. if(dep[x]<dep[y])swap(x,y);
  32. for(int i=18;i>=0;i--)if(dep[x]>=dep[y]+(1<<i))ans=min(ans,minn[x][i]),x=fa[x][i];
  33. if(x==y)return ans;
  34. for(int i=18;i>=0;i--)
  35. if(fa[x][i]!=fa[y][i]){
  36. ans=min(ans,min(minn[x][i],minn[y][i]));
  37. x=fa[x][i];y=fa[y][i];
  38. }
  39. return min(ans,min(minn[x][0],minn[y][0]));
  40. }
  41. int main(){
  42. scanf("%d%d",&n,&m);
  43. for(int i=1;i<=n;i++)f[i]=i;
  44. memset(dep,-1,sizeof(dep));
  45. memset(minn,0x3f,sizeof(minn));
  46. memset(first,-1,sizeof(first));
  47. for(int i=1;i<=m;i++){
  48. scanf("%d%d%d",&xx,&yy,&zz);
  49. Edge[i].from=xx;Edge[i].to=yy;Edge[i].weight=zz;
  50. }
  51. sort(Edge+1,Edge+1+m,cmp);
  52. for(int i=1;i<=m;i++)
  53. if(find(Edge[i].from)!=find(Edge[i].to)){
  54. f[find(Edge[i].from)]=find(Edge[i].to);
  55. add(Edge[i].from,Edge[i].to,Edge[i].weight);
  56. add(Edge[i].to,Edge[i].from,Edge[i].weight);
  57. }
  58. dep[find(1)]=0;dfs(find(1));
  59. scanf("%d",&m);
  60. while(m--){
  61. scanf("%d%d",&xx,&yy);
  62. if(~dep[xx]&&~dep[yy])printf("%d\n",lca(xx,yy));
  63. else puts("-1");
  64. }
  65. }

队长讲了还有一中很奇怪的方法可以乱搞。

就是:Bling 并查集!

我们可以想到Kruskal进行的过程中是把两个连通块连起来,中间连的边一定比连通块里面的边要小。

那么我们可以考虑按秩合并。。可以证明这样树的高度是log的。

然后直接暴力求LCA即可

网上是这么说的:

启发式并查集,就是维护每个集合的深度,在合并两个集合的时候把小的那个集合挂在大集合下。

在此题中呢,求最大生成树的同时,不把新加入的一条边作为计算答案的树,而是把两个集合的祖先加入树中,边权就是原来边的两个边权。看到这,不禁产生了疑问,树的边权和形态与求出的最大生成树都不一样,为啥能做???其实没有关系,因为新加入的边不影响

原来集合中两点的答案,合并的两个集合中的点合并后肯定要经过原来这条边,那我把祖先接起来用原来边的边权也是一样的。

但是这么做,由于使用了启发式合并,那么最后新的树高度可以证明不会超过logn(其实我也不会证大笑),那么我们不用倍增处理这棵树,直接暴力求lca即可,不仅代码短,而且常数小!!!

  1. // by SiriusRen
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. #define N 105000
  7. int n,m,tot=0,xx,yy,zz;
  8. int first[N],v[N*10],next[N*10],w[N*10],f[N],dep[N],fa[N],size[N],minn[N];
  9. int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
  10. struct EDGE{int from,to,weight;}Edge[50500];
  11. void add(int x,int y,int z){w[tot]=z,v[tot]=y;next[tot]=first[x];first[x]=tot++;}
  12. bool cmp(EDGE x,EDGE y){return x.weight>y.weight;}
  13. void dfs(int x){
  14. for(int i=first[x];~i;i=next[i])
  15. if(dep[v[i]]==-1){
  16. dep[v[i]]=dep[x]+1;
  17. fa[v[i]]=x;minn[v[i]]=w[i];
  18. dfs(v[i]);
  19. }
  20. }
  21. void lca(int x,int y){
  22. int ans=0x3fffffff;
  23. if(dep[x]>dep[y])swap(x,y);
  24. while(dep[x]!=dep[y])ans=min(minn[y],ans),y=fa[y];
  25. while(x!=y){
  26. ans=min(ans,min(minn[x],minn[y]));
  27. x=fa[x];y=fa[y];
  28. }
  29. printf("%d\n",ans);
  30. return;
  31. }
  32. int main(){
  33. scanf("%d%d",&n,&m);
  34. for(int i=1;i<=n;i++)size[i]=1;
  35. for(int i=1;i<=n;i++)f[i]=i;
  36. memset(dep,-1,sizeof(dep));
  37. memset(first,-1,sizeof(first));
  38. memset(minn,0x3f,sizeof(minn));
  39. for(int i=1;i<=m;i++){
  40. scanf("%d%d%d",&xx,&yy,&zz);
  41. Edge[i].from=xx;Edge[i].to=yy;Edge[i].weight=zz;
  42. }
  43. sort(Edge+1,Edge+1+m,cmp);
  44. for(int i=1;i<=m;i++){
  45. int fx=find(Edge[i].from),fy=find(Edge[i].to);
  46. if(fx!=fy){
  47. if(size[fx]>size[fy])swap(fx,fy);
  48. f[fx]=fy;size[fy]+=fx;
  49. add(fx,fy,Edge[i].weight);add(fy,fx,Edge[i].weight);
  50. }
  51. }
  52. dep[find(1)]=0;dfs(find(1));
  53. scanf("%d",&m);
  54. while(m--){
  55. scanf("%d%d",&xx,&yy);
  56. if(~dep[xx]&&~dep[yy])lca(xx,yy);
  57. else puts("-1");
  58. }
  59. }

NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并的更多相关文章

  1. 【bzoj4668】冷战 并查集按秩合并+朴素LCA

    题目描述 1946 年 3 月 5 日,英国前首相温斯顿·丘吉尔在美国富尔顿发表“铁幕演说”,正式拉开了冷战序幕. 美国和苏联同为世界上的“超级大国”,为了争夺世界霸权,两国及其盟国展开了数十年的斗争 ...

  2. 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增

    倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...

  3. NOIP2013 D1T3 货车运输

    [NOIP2013T3]货车运输 背景 noip2013day1 描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重 量限制,简称限重.现在有 q 辆货 ...

  4. 洛谷P1967货车运输——倍增LCA

    题目:https://www.luogu.org/problemnew/show/P1967 就是倍增LCA的裸题,注意一些细节即可. 代码如下: #include<iostream> # ...

  5. NOIP2013 D1T3 货车运输 zz耻辱记

    目录 先来证明下lemma: 图上2点间最小边权最大的路径一定在MST上 感性理解下: 每次kruskal algo都连接最大的不成环边 此时有2个未联通的联通块被连起来. 那么考虑u, v两点的联通 ...

  6. xsy 2018 【NOIP2013】货车运输

    [NOIP2013]货车运输 Description A 国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有q辆货车在运输货物,司机们想知道每辆车在不超 ...

  7. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  8. LCA tarjan+并查集POJ1470

    LCA tarjan+并查集POJ1470 https://www.cnblogs.com/JVxie/p/4854719.html 不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻 ...

  9. NOIP2013 货车运输 倍增

    问题描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能 ...

随机推荐

  1. Deutsch lernen (14)

    1.    das Abseits, -  越位 Der Linienrichter winkte Abseits.  winken - winkte - gewunken  示意 2.    abs ...

  2. 时序分析:ARMA方法(平稳序列)

    憔悴到了转述中文综述的时候了........ 在统计学角度来看,时间序列分析是统计学中的一个重要分支, 是基于随机过程理论和数理统计学的一种重要方法和应用研究领域.  时间序列按其统计特性可分为平稳性 ...

  3. C++对象的内存模型

    1. 普通对象模型 对象是如何在内存中布局的? 成员 存放位置 访问范围 非静态数据成员 每一个对象体内 为该对象专有 静态数据成员 程序的静态存储区内,只有一份实体 为该类所有对象共享 成员函数(静 ...

  4. BZOJ 5466: [Noip2018]保卫王国 动态DP

    Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...

  5. 爬取某网站景区列表并保存为csv文件

    网址:http://www.halehuo.com/jingqu.html 经过查看可以发现,该景区页面没有分页,不停的往下拉,页面会进行刷新显示后面的景区信息 通过使用浏览器调试器,发现该网站使用的 ...

  6. 50.常用的query查询方式

    主要知识点 match all match multi match range query term query terms query exist query         1.match all ...

  7. 4.Thymeleaf的常用标签

    一.常用标签 二.foreach案例 1.创建项目 2. 创建Student.java package cn.kgc.pojo; /** * Created by Administrator on 2 ...

  8. 2.Git可视化操作

    1.在本地新建版本库 首先,我们打开Git GUI是这样的一个界面,选择第一项,新建版本库. 然后选择你需要进行版本管理的项目路径,我选择了一个LoginDemo的项目. 当你创建了版本库的时候,你可 ...

  9. display显示属性理解

    display属性设置一个元素应如何显示,是我们在前端开发中常常使用的一个属性,其中,最常见的有: 目录 display:none;表示此元素将不被显示. display:block;将元素显示为块元 ...

  10. dubbo-源码阅读之javaspi&javasist简单使用

    dubbo可扩展的点的类的对象创建 都是用类似javaspi和javasist的思想来做的.所以看后面代码 先熟悉一下java的SPI和javasist的使用 如ServicesConfig的代码 p ...