• 货车运输


    原题链接:https://www.luogu.org/problem/show?pid=1967

    说出来你可能不信,这题我爆了一整天的0。想获取更多真相者,请打开洛谷p1967题评测界面,输入用户名“zx2000412”,你就知道现状有多惨烈。

    先说说思路吧。听说这道题是最大生成树,我就按照这个思路往下展开的。

    一开始的想法是跑一遍最大生成树,以获得的树的边再建一图,对于每次询问跑一次bfs。

    后来发现时间复杂度是平方阶,肯定不是标算,只拿了5分(我不得不说,这题数据真心强

    考虑到每次是在树上询问任意两点最大载重量,遂想到LCA做法。最后跑了380ms,差强人意。

    听说树剖做法更快?改天试一下。

    依然是要处理出最大生成树,存起来。用两个倍增数组,一个是f[i][j],代表从i这个点向上蹦2^j个点是哪个点,另一个是minval[i][j]代表从i向上蹦2^j个点时经过路径的最小值。

    (求最大载重量为什么算最小?道理很显然啊,不可以超重,所以最大载重量一定是最小道路承载量)

    求生成树是裸的Kruskal,并查集做法,这里不再赘述。细节部分详见代码。(这年头谁还用Prim)

    然后是二次建图,这里有一步dfs预处理,把这个图转换成树一样的形式(虽然本来就是树)dep数组记录深度方便lca使用。

    求LCA时也需要先预处理倍增数组,然后蹦的时候顺带维护一下ans就好。

    参考代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define maxn 50005
      6 #define INF 888888888888
      7 using namespace std;
      8 typedef long long ll;
      9 //------------------------变量与结构体---------------------------
     10 ll dep[maxn],f[maxn][21],minval[maxn][21];
     11 ll n,m,q,x,y;
     12 ll tot = 0,head[maxn],father[maxn],fa[maxn];
     13 struct Edge{
     14     ll from,to,dis;
     15     bool operator<(const Edge& rhs)const{
     16         return dis > rhs.dis;
     17     }
     18 };
     19 Edge edge_T[maxn];
     20 Edge edge[maxn];
     21 //-------------------------辅助类函数-----------------------------
     22 ll read(){
     23     ll num = 0;
     24     char c;
     25     bool flag = false;
     26     while ((c = getchar()) == ' ' || c == '
    ' || c == '
    ');
     27     if (c == '-')
     28         flag = true;
     29     else
     30         num = c - '0';
     31     while (isdigit(c = getchar()))
     32         num = num * 10 + c - '0';
     33     return (flag ? -1 : 1) * num;
     34 }
     35 ll min_ele(ll a,ll b,ll c){
     36     ll t = min(a,b);
     37     return min(t,c);
     38 }
     39 //---------------------Kruskal与二次建图--------------------------
     40 
     41 void init_ufs(){
     42     for (register ll i=1;i<=n;i++)
     43         father[i] = i;
     44 }
     45 
     46 ll find(ll x){
     47     if (father[x] == x)
     48         return x;
     49     father[x] = find(father[x]);
     50     return father[x];
     51 }
     52 void merge(ll x, ll y){
     53     x = find(x);
     54     y = find(y);
     55     father[y] = x;
     56 }
     57 
     58 void add_edge(ll from,ll to,ll dis){
     59     edge[++tot].from = head[from];
     60     edge[tot].to = to;
     61     edge[tot].dis = dis;
     62     head[from] = tot;
     63 }
     64 void dfs(ll x){
     65     for (register ll i = head[x];i;i = edge[i].from){
     66         ll v = edge[i].to;
     67         if (v == fa[x])
     68             continue;      
     69         f[v][0] = x;
     70         minval[v][0] = edge[i].dis;
     71         dep[v] = dep[x] + 1;
     72         fa[v] = x;
     73         dfs(v);
     74     }
     75 }
     76 //--------------------------LCA相关------------------------------
     77 void init_lca(){
     78     for (register ll i=1;i<=20;i++)
     79         for (register ll j=1;j<=n;j++){
     80             f[j][i] = f[ f[j][i-1] ][i-1];
     81             minval[j][i] = min(minval[j][i-1],minval[ f[j][i-1] ][i-1]);
     82         }
     83 }
     84 ll lca(ll x,ll y){
     85     ll ans = INF;
     86     if (dep[x]>dep[y])
     87         swap(x,y);
     88     for (register ll i=20;i>=0;i--)
     89         if (dep[f[y][i]]>=dep[x]){
     90             ans=min(ans,minval[y][i]);
     91             y=f[y][i];
     92         }
     93     if (x==y)
     94         return ans;
     95     for (register ll i=20;i>=0;i--){
     96         if (f[x][i] != f[y][i]){
     97             ans = min_ele(minval[x][i],minval[y][i],ans);
     98             x = f[x][i];
     99             y = f[y][i];
    100         }
    101     }
    102     ans = min_ele(minval[x][0],minval[y][0],ans);
    103     return ans;
    104 }
    105 //----------------------------主函数----------------------------
    106 int main(){
    107     n = read();m = read();
    108     for (register ll i=1;i<=m;i++){
    109         edge_T[i].from = read();
    110         edge_T[i].to = read();
    111         edge_T[i].dis = read();
    112     }
    113     sort(edge_T+1,edge_T+m+1);
    114     init_ufs();
    115     for (register ll i=1;i<=m;i++)
    116         if (find(edge_T[i].from) != find(edge_T[i].to)){
    117             merge(edge_T[i].from,edge_T[i].to);
    118             add_edge(edge_T[i].from, edge_T[i].to, edge_T[i].dis);
    119             add_edge(edge_T[i].to, edge_T[i].from, edge_T[i].dis);
    120         }
    121     for (register ll i=1;i<=n;i++)
    122         if (father[i] == i){
    123             fa[i] = i;dep[i] = 1;dfs(i);
    124         }
    125     init_lca();
    126     q = read();
    127     for (register ll i=1;i<=q;i++){
    128         x = read();y = read();
    129         if (find(x) == find(y))
    130                printf("%lld
    ",lca(x,y));
    131         else
    132             printf("-1
    ");
    133     }
    134     return 0;
    135 }
  • 相关阅读:
    修改SharePoint 2013中item Created by 信息
    用powershell批量新增user profile
    如何发一封回复的时候收件人和发件人不同的邮件
    SharePoint 2013配置 Workflow Manager
    正则表达式
    go
    HTML5
    js-example
    css3
    jquery-example
  • 原文地址:https://www.cnblogs.com/OIerShawnZhou/p/7636253.html
Copyright © 2020-2023  润新知