• 洛谷T1967 货车运输 Kruskal最大生成树&&倍增LCA


    这题的题意是:对于每组x、y,求x到y路径上最小边权的最大值。


    于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大。


    有了树之后,要求路径,那就要考虑LCA。


    首先,这题可以树剖,但是我太懒了,于是写了倍增233


    具体搞法:


    Kruskal跑出最大生成树,然后在树上倍增LCA,处理出2个数组:fa[][]和minv[][];fa[][]表示第2^k个父亲是谁,minv[][]表示当前节点到其第2^k个父亲的路径上的最小边权。对于每次查询,在求LCA的同时,沿路将各段的minv取并即可,每次时间与LCA查询相同,为logn。


    现在还有一个问题:图不一定是连通的。。。不能无脑LCA。。。


    解决这个问题的方法是:在Kruskal结束后,对并查集中的每个集合各进行一次LCA预处理。对于每次查询,先判断两节点是否属于同一集合,若属于同一集合则进行LCA查询,否则直接输出-1。


    代码如下:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<ctime>
      6 #include<cstdlib>
      7 
      8 #include<string>
      9 #include<stack>
     10 #include<queue>
     11 #include<vector>
     12 #include<algorithm>
     13 #include<map>
     14 #include<set>
     15 
     16 #define inf 2147483647
     17 #define ri register int
     18 #define ll long long
     19 
     20 using namespace std;
     21 
     22 inline void read(int &x){
     23     x=0;
     24     char t=getchar();
     25     bool f=0;
     26     
     27     while(t<'0' || t>'9'){
     28         if(t=='-')f=1;
     29         t=getchar();
     30     }
     31     
     32     while(t>='0' && t<='9'){
     33         x=(x<<3)+(x<<1)+t-'0';
     34         t=getchar();
     35     }
     36     
     37     if(f)x=-x;
     38 }
     39 
     40 inline void addedge(int,int,int);
     41 int u[100010];
     42 int v[100010];
     43 int w[100010];
     44 int first[10005];
     45 int next[100010];
     46 int pe=0;  //邻接表(无向)
     47 
     48 inline bool cmp(const int a,const int b);
     49 int ha_e[50005];  //边排序辅助数组 
     50 
     51 inline void Kruskal();
     52 int find(int);
     53 int bcj[10005];  //并查集 
     54 bool use[50005];  //记录边是否使用 
     55 
     56 void dfs(int,int);  //LCA预处理,直接父亲及最小边权在上层处理 
     57 bool vis[10005];  //防止重复访问 
     58 int dep[10005];  //节点深度 
     59 int fa[10005][15];  //LCA表 
     60 int minv[10005][15];  //节点到其第2^k个父亲路径间的最小边权 
     61 
     62 inline int query(int,int);  //查询路径最小边权 
     63 
     64 int n,m,q;
     65 int rest;
     66 int x,y,z;
     67 
     68 int main(){
     69     read(n);read(m);
     70     rest=n;
     71     
     72     for(ri i=1;i<=m;i++){
     73         read(x);read(y);read(z);
     74         
     75         addedge(x,y,z);
     76         addedge(y,x,z);
     77         
     78         ha_e[i]=i<<1;
     79     }  //建初始图 
     80     
     81     sort(ha_e+1,ha_e+1+m,cmp);  //边权从大到小排序 
     82     Kruskal();  //生成最大生成树,记录需要使用的边 
     83     
     84     memset(vis,0,sizeof(vis));
     85     
     86     for(ri i=1;i<=n;i++)  //生成2个倍增表 
     87         if(!vis[find(i)]){
     88             fa[i][0]=0;  //根节点无父亲 
     89             minv[i][0]=inf;
     90             dfs(i,1);  //以i号节点为根进行遍历 
     91         }
     92     
     93     read(q);
     94     
     95     for(ri i=1;i<=q;i++){
     96         read(x);read(y);
     97         
     98         if(find(x)!=find(y)){
     99             printf("-1
    ");
    100             continue;
    101         }
    102         
    103         if(dep[x]>dep[y])swap(x,y);  //使y更深 
    104         
    105         printf("%d
    ",query(x,y));
    106     }
    107     
    108     return 0;
    109 }
    110 
    111 inline void addedge(int x,int y,int z){
    112     pe++;
    113     u[pe]=x;
    114     v[pe]=y;
    115     w[pe]=z;
    116     next[pe]=first[x];
    117     first[x]=pe;
    118 }
    119 
    120 inline bool cmp(const int a,const int b){
    121     return w[a]>w[b];
    122 }
    123 
    124 int find(int x){
    125     if(bcj[x]==x)return x;
    126     else return bcj[x]=find(bcj[x]);
    127 }
    128 
    129 inline void Kruskal(){
    130     int x,y,fx,fy;
    131     
    132     for(ri i=1;i<=n;i++)bcj[i]=i;
    133     memset(use,0,sizeof(use));
    134     
    135     for(ri i=1;i<=m && rest>1;i++){
    136         x=u[ha_e[i]];
    137         y=v[ha_e[i]];
    138         fx=find(x);
    139         fy=find(y);
    140         
    141         if(fx!=fy){
    142             bcj[fx]=fy;
    143             rest--;
    144             use[ha_e[i]>>1]=1;
    145         }
    146     }
    147 }
    148 
    149 void dfs(int s,int h){
    150     int e,t;
    151     
    152     dep[s]=h;
    153     vis[s]=1;
    154     
    155     for(ri i=1;(1<<i)<h;i++){  //i=0已在上层处理;若1<<i==h则恰有一个节点越界 
    156         fa[s][i]=fa[fa[s][i-1]][i-1];
    157         minv[s][i]=min(minv[s][i-1],minv[fa[s][i-1]][i-1]);
    158     }
    159     
    160     e=first[s];
    161     t=v[e];
    162     
    163     while(e){
    164         if(!vis[t] && use[(e+1)>>1]){
    165             fa[t][0]=s;
    166             minv[t][0]=w[e];
    167             dfs(t,h+1);
    168         }
    169         
    170         e=next[e];
    171         t=v[e];
    172     }
    173 }
    174 
    175 inline int query(int x,int y){
    176     int dt=dep[y]-dep[x];
    177     int ans=inf;
    178     
    179     for(ri i=0;(1<<i)<=dt;i++)
    180         if((1<<i)&dt){
    181             ans=min(ans,minv[y][i]);
    182             y=fa[y][i];
    183         }
    184     
    185     if(x==y)return ans;
    186     
    187     for(ri i=13;i>=0;i--)
    188         if(fa[x][i]!=fa[y][i]){
    189             ans=min(ans,minv[x][i]);
    190             ans=min(ans,minv[y][i]);
    191             
    192             x=fa[x][i];
    193             y=fa[y][i];
    194         }
    195     
    196     ans=min(ans,minv[x][0]);
    197     ans=min(ans,minv[y][0]);
    198     
    199     return ans;
    200 }
  • 相关阅读:
    4种方法帮你解决IntelliJ IDEA控制台中文乱码问题
    万字长文:解读区块链7类共识算法
    CoralCache:一个提高微服务可用性的中间件
    探究Python源码,终于弄懂了字符串驻留技术
    OAuth:每次授权暗中保护你的那个“MAN”
    厉害了!这群95后正在用三维成像技术让科幻变成现实
    华为云FusionInsight MRS在金融行业存算分离的实践
    【新春特辑】发压岁钱、看贺岁片、AI写春联……华为云社区给大家拜年了
    Java实现 蓝桥杯 算法训练 天数计算
    WebRTC框架中的硬件加速
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/7765685.html
Copyright © 2020-2023  润新知