zoukankan      html  css  js  c++  java
  • P2245 星际导航

    题目描述

    sideman 做好了回到Gliese星球的硬件准备,但是sideman的导航系统还没有完全设计好。为了方便起见,

    我们可以认为宇宙是一张有N 个顶点和M 条边的带权无向图,顶点表示各个星系,两个星系之间有边就表示两个星系之间可以直航,

    而边权则是航行的危险程度。

    sideman 现在想把危险程度降到最小,具体地来说,就是对于若干个询问(A,B),sideman 想知道从顶点A

    航行到顶点B 所经过的最危险的边的危险程度值最小可能是多少。作为 sideman的同学,你们要帮助sideman

    返回家园,兼享受安全美妙的宇宙航行。所以这个任务就交给你了。

    输入输出格式

    输入格式:

    第一行包含两个正整数N和M,表示点数和边数。

    之后M行,每行三个整数A,B和L,表示顶点A和B之间有一条边长为L的边。顶点从1开始标号。

    下面一行包含一个正整数Q,表示询问的数目。

    之后Q行,每行两个整数 A和B,表示询问A和B之间最危险的边危险程度的可能最小值。

    输出格式:

    对于每个询问, 在单独的一行内输出结果。如果两个顶点之间不可达, 输出impossible。

    输入输出样例

    输入样例#1: 
    4 5
    1 2 5
    1 3 2
    2 3 11
    2 4 6
    3 4 4
    3
    2 3
    1 4
    1 2
    
    输出样例#1: 
    5
    4
    5
    

    说明

    对于 40%的数据,满足 N≤1000,M≤3000,Q≤1000

    对于 80%的数据,满足 N≤10000,M≤105,Q≤1000

    对于 100% 的数据,满足 N≤105,M≤3×105,Q≤105,L≤109,数据不保证没有重边和自环。

    代码

    kruskal重构树裸题,做法同货车运输

    最危险的边危险程度的可能最小值,也就是最大值最小

    我们边权按升序排序,val[lca(x,y)]即为答案

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200000+100,maxm=200000+100,md=20+5;
    int head[maxn],val[maxn],f[maxn],dep[maxn],lg[maxn]; 
    int ff[maxn][md];
    int size=0,cnt=0;
    struct tree
    {
        int to,next;
    }e[maxm<<1];
    struct edge
    {
        int u,v,val;
    }E[maxm<<1];
    int n,m;
    void init()
    {
        for(int i=1;i<=n;i++)
        f[i]=i;
    }
    int find(int x)
    {
        return f[x]==x?x:f[x]=find(f[x]);
    }
    void addedge(int u,int v)
    {
        e[++size].to=v;e[size].next=head[u];head[u]=size;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    bool cmp(const edge&a,const edge&b)
    {
        return a.val>b.val;
    }
    void kruskal()
    {
        for(int i=1;i<=m;i++)
        {
            int u=E[i].u,v=E[i].v;
            int fu=find(u),fv=find(v);
            if(fu!=fv)
            {
            cnt++;
            f[cnt]=f[fu]=f[fv]=cnt;
            val[cnt]=E[i].val;
            addedge(cnt,fu);addedge(fu,cnt);
            addedge(fv,cnt);addedge(cnt,fv);
            }
    
        }
    }
    void dfs(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        ff[u][0]=fa;
        for(int i=1;i<=lg[dep[u]];i++)
        ff[u][i]=ff[ff[u][i-1]][i-1];
        for(int i=head[u];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==fa)continue;
            dfs(to,u);
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
        swap(x,y);
        while(dep[x]>dep[y])
        x=ff[x][lg[dep[x]-dep[y]]];
        if(x==y)
        return x;
        for(int i=lg[dep[x]];i>=0;i--)
        if(ff[x][i]!=ff[y][i])x=ff[x][i],y=ff[y][i];
        return ff[x][0];
    }
    int main()
    {
        n=read(),m=read();cnt=n;
        init();
        for(int i=1;i<=m;i++)
        E[i].u=read(),E[i].v=read(),E[i].val=read();
        sort(E+1,E+1+m,cmp);
        kruskal();
        for(int i=1;i<=n;i++)
        lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
        for(int i=1;i<=cnt;i++)
        if(!dep[i])
        dfs(find(i),0); 
        int k=read();
        for(int i=1;i<=k;i++)
        {
            int x=read(),y=read();
            if(find(x)!=find(y))printf("-1
    ");
            else printf("%d
    ",val[lca(x,y)]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    PHP数组操作,数组排序,数组元素操作,数组元素定位
    提高PHP编程效率的53个要点
    javascript的一些简单的应用
    数字时钟
    一个限定变量范围的小技巧
    windows编程学习——1 关闭窗口不退出
    比木马NB多了
    模拟时钟
    恶搞程序——黑屏
    用白色画笔再画一遍,代替擦除
  • 原文地址:https://www.cnblogs.com/DriverBen/p/10815149.html
Copyright © 2011-2022 走看看