洛谷 P2245 星际导航 解题报告

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。

说明

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

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

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


真是的,不爱倍增了,拍了好久啊。。

思路:求最小生成树以后打树上倍增

错误点:
倍增跳到同一深度后没有判是否已经相等
堆优化的prim应该不是每次进队都加边
倍增同一深度后向上跳时应该先更新答案再跳(我居然可以错的这么蠢。。)


Code:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N=100010;
int head0[N],edge0[N<<1],to0[N<<1],next0[N<<1],cnt0;
void add0(int u,int v,int w)
{
    edge0[++cnt0]=w;to0[cnt0]=v;next0[cnt0]=head0[u];head0[u]=cnt0;
}
int head[N],edge[N<<1],to[N<<1],next[N<<1],cnt;
void add(int u,int v,int w)
{
    edge[++cnt]=w;to[cnt]=v;next[cnt]=head[u];head[u]=cnt;
}
int used[N],m,n,Q,dep[N],anc[N];
void dfs(int now,int an)
{
    used[now]=1;
    anc[now]=an;
    for(int i=head0[now];i;i=next0[i])
    {
        int v=to0[i],w=edge0[i];
        if(!used[v])
            dfs(v,an);
    }
}
void init()
{
    memset(used,0,sizeof(used));
    for(int i=1;i<=n;i++)
        if(!used[i])
        {
            dfs(i,i);
            add0(0,i,0);
        }
}
struct node
{
    int from,to,w;
    bool friend operator <(node n1,node n2)
    {
        return n1.w>n2.w;
    }
    node(){}
    node(int from,int to,int w)
    {
        this->from=from;
        this->to=to;
        this->w=w;
    }
};
priority_queue <node > q;
void prim()
{
    memset(used,0,sizeof(used));
    for(int i=head0[0];i;i=next0[i])
    {
        int v=to0[i],w=edge0[i];
        node tt(0,v,w);
        q.push(tt);
    }
    int cntt=0;
    while(!q.empty()&&cntt<n)
    {
        int u=q.top().to;
        if(used[u]) {q.pop();continue;}
        add(q.top().from,q.top().to,q.top().w);
        add(q.top().to,q.top().from,q.top().w);
        used[u]=1;
        cntt++;
        q.pop();
        for(int i=head0[u];i;i=next0[i])
        {
            int v=to0[i],w=edge0[i];
            if(!used[v])
            {
                node tt(u,v,w);
                q.push(tt);
            }
        }
    }
}
int f[N][21],fw[N][21];
void dfs2(int now)
{
    used[now]=1;
    for(int i=head[now];i;i=next[i])
    {
        int v=to[i],w=edge[i];
        if(!used[v])
        {
            f[v][0]=now;
            fw[v][0]=w;
            dep[v]=dep[now]+1;
            dfs2(v);
        }
    }
}
void init2()
{
    memset(used,0,sizeof(used));
    dfs2(0);
    for(int j=1;j<=20;j++)
        for(int i=0;i<=n;i++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            fw[i][j]=max(fw[i][j-1],fw[f[i][j-1]][j-1]);
        }
}
void query(int x,int y)
{
    int ans=0;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
        {
            ans=max(ans,fw[x][i]);
            x=f[x][i];
        }
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            ans=max(ans,max(fw[x][i],fw[y][i]));
            x=f[x][i],y=f[y][i];
        }
    if(x!=y)
        ans=max(ans,max(fw[x][0],fw[y][0]));
    printf("%d\n",ans);
}
int main()
{
    freopen("data.out","r",stdin);
    freopen("bf.out","w",stdout);
    scanf("%d%d",&n,&m);
    int u,v,w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add0(u,v,w),add0(v,u,w);
    }
    init();
    prim();
    init2();
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)
    {
        scanf("%d%d",&u,&v);
        if(anc[u]!=anc[v])
            printf("impossible\n");
        else
            query(u,v);
    }
    return 0;
}

2018.6.30

posted @ 2018-06-30 16:07  露迭月  阅读(139)  评论(0编辑  收藏  举报