码迷,mamicode.com
首页 > 其他好文 > 详细

WOJ#2423 安全出行Safe Travel

时间:2019-10-20 17:58:10      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:题解   while   name   names   jks   输出   using   sizeof   str   

描述

  精灵最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的 地是牛棚_i)。每一个精灵只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经。所以它们在牛_i到牛棚_i之前的最后一条牛路上等牛_i。当然,牛不愿意遇到Gremlins,所以准备找 一条稍微不同的路经从牛棚_1走到牛棚_i。所以,请你为每一头牛_i找出避免精灵的最短路经的长度。

  和以往一样, 农场上的M (2 <= M <= 200,000)条双向牛路编号为1-M并且能让所有牛到 达它们的目的地, N(3 <= N <= 100,000)个编号为1-N的牛棚.牛路i连接牛棚a_i (1 <= a_i <= N)和b_i (1 <= b_i <= N)并且需要时间t_i (1 <=t_i <= 1,000)通过。没有两条牛路连接同样的牛棚,所有牛路满足a_i!=b_i.在所有数据中,牛_i使用的牛棚_1到牛 棚_i的最短路经是唯一的。

输入

 

  第一行: 两个空格分开的数, N和M

  第2-M+1行: 三个空格分开的数a_i, b_i,和t_i

输出

  第1-N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间。如果这样的路经不存在,输出-1。

题解

  智商不够,数据结构来凑。提供一个比较暴力的思路。

  先搞出最短路树。我们考虑加入一条非树边,两端点为u、v,权值为w,如果它会影响点x的答案,那么x的答案会变成d[u]+d[v]+w-d[x](d[x]为起点到x的最短路)。我们再考虑加入一条非树边会对哪些点产生影响:容易发现,会受影响的点是u到v的路径上出去lca的点。由于要使每个点的答案最小,所以这就是一个区间取min的问题,可以用树链剖分解决。放上代码:

#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define INF 0x3f3f3f3f
int n,m;
int num=1,f[N],vst[N<<2];
struct node{
    int u,v,w,nxt;
}e[N<<2];
void add(int u,int v,int w){e[++num]=(node){u,v,w,f[u]};f[u]=num;}
//build graph
#define pii pair<int,int>
#define mp make_pair
int d[N],vis[N];
void dijkstra(){
    memset(d,0x3f,sizeof(d));
    priority_queue<pii,vector<pii>,greater<pii> > q;
    d[1]=0;q.push(mp(d[1],1));
    while(!q.empty()){
        pii t=q.top();q.pop();
        int dd=t.first,u=t.second;
        if(vis[u]) continue;vis[u]=1;
        for(int i=f[u];i;i=e[i].nxt){
            int v=e[i].v,w=e[i].w;
            if(d[v]>dd+w){d[v]=dd+w;q.push(mp(d[v],v));}
        }
    }
}
//shortest path
namespace TREE{
    int num,f[N];
    struct node{
        int u,v,nxt;
    }e[N<<1];
    void add(int u,int v){
        e[++num]=(node){u,v,f[u]};f[u]=num;
        e[++num]=(node){v,u,f[v]};f[v]=num;
    }
    //build graph
    #define lc (p<<1)
    #define rc (p<<1|1)
    struct tree{
        int l,r,mx;
    }t[N<<2];
    void up(int p){t[p].mx=max(t[lc].mx,t[rc].mx);}
    void now(int p,int v){t[p].mx=min(t[p].mx,v);}
    void down(int p){if(t[p].mx<INF) now(lc,t[p].mx),now(rc,t[p].mx);}
    void build(int p,int l,int r){
        t[p].l=l;t[p].r=r;
        if(l==r){t[p].mx=INF;return;}
        int mid=(l+r)>>1;
        build(lc,l,mid);build(rc,mid+1,r);up(p);
    }
    void update(int p,int l,int r,int v){
        if(v>=t[p].mx||l>r) return;
        if(l<=t[p].l&&t[p].r<=r){now(p,v);return;}
        int mid=(t[p].l+t[p].r)>>1;down(p);
        if(l<=mid) update(lc,l,r,v);
        if(r> mid) update(rc,l,r,v);
        up(p);
    }
    int query(int p,int k){
        if(t[p].l==t[p].r){return t[p].mx;}
        int mid=(t[p].l+t[p].r)>>1;down(p);
        if(k<=mid) return query(lc,k);
        else return query(rc,k);
    }
    //segment tree
    int cnt,dep[N],faz[N],seg[N],siz[N],son[N],top[N];
    void dfs1(int u,int fa,int d){
        dep[u]=d;faz[u]=fa;siz[u]=1;
        for(int i=f[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(v==fa) continue;
            dfs1(v,u,d+1);siz[u]+=siz[v];
            if(siz[v]>siz[son[u]]) son[u]=v;
        }
    }
    void dfs2(int u,int st){
        seg[u]=++cnt;top[u]=st;
        if(!son[u]) return;dfs2(son[u],st);
        for(int i=f[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(v==faz[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    void change(int x,int y,int v){
        int xx=top[x],yy=top[y];
        while(xx^yy){
            if(dep[xx]<dep[yy]){swap(xx,yy);swap(x,y);}
            update(1,seg[xx],seg[x],v);
            x=faz[xx];xx=top[x];
        }
        if(dep[x]>dep[y]) swap(x,y);
        update(1,seg[x]+1,seg[y],v);
    }
    //tree dissection
}
int main(){
    int x,y,z;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);}
    dijkstra();
    for(int i=2;i<=num;i+=2){
        int u=e[i].u,v=e[i].v,w=e[i].w;
        if(d[u]+w==d[v]||d[v]+w==d[u]){TREE::add(u,v);vst[i]=vst[i^1]=1;}
    }
    TREE::dfs1(1,0,1);TREE::dfs2(1,1);TREE::build(1,1,n);
    for(int i=2;i<=num;i+=2){
        if(vst[i]) continue;
        int u=e[i].u,v=e[i].v,w=e[i].w,tmp=d[u]+d[v]+w;
        TREE::change(u,v,tmp);
    }
    for(int i=2;i<=n;i++){
        int ans=TREE::query(1,TREE::seg[i]);
        if(ans==INF) puts("-1");
        else printf("%d\n",ans-d[i]);
    }
    return 0;
}

 

WOJ#2423 安全出行Safe Travel

标签:题解   while   name   names   jks   输出   using   sizeof   str   

原文地址:https://www.cnblogs.com/doyo2019/p/11708076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!