• 洛谷 P1967 货车运输


    题目传送门

    解题思路:

    先求出整个图的最大生成树,然后做树上LCA.

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 
      5 using namespace std;
      6 
      7 int n,m,tot,head[10001],fa[10001],_tot,d[10001];
      8 int p[10001][21],q,fv[10001][21],ans = 0x7f7f7f7f;
      9 bool vis[10001];
     10 struct kkk{
     11     int vi,to,from;
     12 }e[100002];
     13 struct k2 {
     14     int next,v,to;
     15 }e1[100002];
     16 
     17 inline int find_father(int x) {
     18     if(fa[x] == x) return fa[x];
     19     return fa[x] = find_father(fa[x]);
     20 }
     21 
     22 inline void add(int x,int y,int z) {
     23     e[++tot].to = y;
     24     e[tot].vi = z;
     25     e[tot].from = x;
     26 }
     27 
     28 inline bool cmp(kkk a,kkk b) {
     29     return a.vi > b.vi;
     30 }
     31 
     32 inline void add2(int x,int y,int z) {
     33     e1[++_tot].to = y;
     34     e1[_tot].next = head[x];
     35     e1[_tot].v = z;
     36     head[x] = _tot;
     37 }
     38 
     39 inline void kruskal() {
     40     for(int i = 1;i <= n; i++) 
     41         fa[i] = i;
     42     sort(e+1,e+1+m+m,cmp);//因为是双向边,所以要加2*m,卡了好久,感谢Candy?大佬 
     43     for(int i = 1;i <= m + m; i++) {
     44         int t = e[i].to;
     45         int f = e[i].from;
     46         int tt = find_father(t);
     47         int ff = find_father(f);
     48         if(tt != ff) {
     49             add2(t,f,e[i].vi);
     50             add2(f,t,e[i].vi);
     51             fa[tt] = ff;
     52         }
     53     }
     54 }
     55 
     56 inline void dfs(int u) {
     57     vis[u] = 1;
     58     for(int i = 1;(1 << i) <= d[u]; i++){
     59         p[u][i] = p[p[u][i-1]][i-1];
     60         fv[u][i] = min(fv[u][i-1],fv[p[u][i-1]][i-1]);
     61     }
     62     for(int i = head[u];i != 0; i = e1[i].next) {
     63         int oo = e1[i].to;
     64         if(!vis[oo]) {
     65             d[oo] = d[u] + 1;
     66             fv[oo][0] = e1[i].v;//记录自己到父亲的边的值 
     67             p[oo][0] = u;//记录自己的父亲 
     68             dfs(oo);
     69         }
     70     }
     71 }
     72 
     73 inline int lca(int x,int y) {
     74     ans = 0x7f7f7f7f;
     75     if(find_father(x) != find_father(y)) return -1;
     76     if(d[x] > d[y])
     77         swap(x,y);
     78     for(int i = 20;i >= 0; i--)
     79         if(d[x] <= d[p[y][i]]) {
     80             ans = min(ans,fv[y][i]);
     81             y = p[y][i];
     82         }
     83     if(x == y) return ans;
     84     for(int i = 20;i >= 0; i--) {
     85         if(p[x][i] != p[y][i]) {
     86             ans = min(ans,min(fv[x][i],fv[y][i]));
     87             x = p[x][i];
     88             y = p[y][i];
     89         }
     90     }
     91     ans = min(ans,min(fv[x][0],fv[y][0]));
     92     return ans;
     93 }
     94 
     95 int main() {
     96     scanf("%d%d",&n,&m);
     97     for(int i = 1;i <= m; i++) {
     98         int x,y,z;
     99         scanf("%d%d%d",&x,&y,&z);
    100         add(x,y,z);
    101         add(y,x,z);
    102     }
    103     kruskal();
    104     for(int i = 1;i <= n; i++)
    105         if(!vis[i]) {
    106             d[i] = 1; 
    107             dfs(i);
    108             p[i][0] = i;
    109             fv[i][0] = 0x7f7f7f7f;
    110         }
    111     scanf("%d",&q);
    112     for(int i = 1;i <= q; i++) {
    113         int x,y;
    114         scanf("%d%d",&x,&y);
    115         printf("%d
    ",lca(x,y));
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    poj 3040 Allowance
    poj 2393 Yogurt factory
    【BZOJ1833】数字计数(ZJOI2010)-数位DP
    【BZOJ4820】硬币游戏(SDOI2017)-概率+高斯消元+KMP
    【BZOJ3626】LCA(LNOI2014)-树链剖分+离线处理
    【BZOJ4817】树点涂色(SDOI2017)-LCT+LCA+线段树
    【BZOJ1135】LYZ(POI2009)-线段树+Hall定理
    【CF392D】Three Arrays-set+multiset
    【51Nod1688】LYKMUL-线段树+乘法原理
    【BZOJ2956】模积和-数论分块
  • 原文地址:https://www.cnblogs.com/lipeiyi520/p/11968010.html
Copyright © 2020-2023  润新知