BZOJ 3694 最短路

3694: 最短路

Time Limit: 5 Sec  Memory Limit: 256 MB
Submit: 303  Solved: 153
[Submit][Status][Discuss]

Description

给出一个n个点m条边的无向图,n个点的编号从1~n,定义源点为1。定义最短路树如下:从源点1经过边集T到任意一点i有且仅有一条路径,且这条路径是整个图1到i的最短路径,边集T构成最短路树。 给出最短路树,求对于除了源点1外的每个点i,求最短路,要求不经过给出的最短路树上的1到i的路径的最后一条边。
 

Input

第一行包含两个数n和m,表示图中有n个点和m条边。
接下来m行,每行有四个数ai,bi,li,ti,表示图中第i条边连接ai和bi权值为li,ti为1表示这条边是最短路树上的边,ti为0表示不是最短路树上的边。

Output

输出n-1个数,第i个数表示从1到i+1的要求的最短路。无法到达输出-1。

Sample Input

5 9
3 1 3 1
1 4 2 1
2 1 6 0
2 3 4 0
5 2 3 0
3 2 2 1
5 3 1 1
3 5 2 0
4 5 4 0

Sample Output

6 7 8 5

HINT

 

 对于100%的数据,n≤4000,m≤100000,1≤li≤100000

 

Source

我的做法是树链剖分+线段树

对于一条不在最短路树的有向边(无向可看成两条有向)u-v,长度L,设t=lca(u,v)

那么对于t-v的路径上所有点x,都可通过1-t-u-v-x

路径长度为d[u]+L+d[v]-d[x]

最小化这个长度,也就是最小化d[u]+d[v]+L

所以我们可以用这个值去更新t-v所有点(不包括t)的最短路长度

这一步可以用线段树操作。。。

/**************************************************************
    Problem: 3694
    User: zhangenming
    Language: C++
    Result: Accepted
    Time:572 ms
    Memory:5952 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define ll long long
#define inf 1e9+10
using namespace std;
inline int read(){
    int x=0;int f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=1e4+10;
struct node{
    int y,next,v;
}e[MAXN];
int linkk[MAXN],len,dis[MAXN],n,m,u[200010],v[200010],l[200010],is[200010],f[MAXN][25],dep[MAXN],son[MAXN],siz[MAXN],dfn[MAXN],dfs_clock,top[MAXN],ans,val,x,y;
struct sig{
    int minn;
}T[MAXN<<2];
inline void insertt(int x,int y,int v){
    e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;e[len].v=v;
}
inline void dfs1(int x,int fa){
    dep[x]=dep[fa]+1;f[x][0]=fa;siz[x]=1;
    for(int i=linkk[x];i;i=e[i].next){
        if(e[i].y!=fa){
            dis[e[i].y]=dis[x]+e[i].v;dfs1(e[i].y,x);siz[x]+=siz[e[i].y];
            if(!son[x]) son[x]=e[i].y;
            else if(siz[e[i].y]>siz[son[x]]) son[x]=e[i].y;
        }
    }
}
inline void dfs2(int x,int fa){
    dfn[x]=++dfs_clock;top[x]=fa;
    if(son[x]) dfs2(son[x],fa);
    for(int i=linkk[x];i;i=e[i].next){
        if(!dfn[e[i].y]&&e[i].y!=fa){
            dfs2(e[i].y,e[i].y);
        }
    }
}
inline void getanser(){
    for(int i=1;i<=20;i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[f[j][i-1]][i-1];
        }
    }
}
inline int lca(int x,int y){
    if(x==y) return x;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--){
        if(dep[x]-(1<<i)>=dep[y]) x=f[x][i];
    }
    if(x==y) return x; 
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]&&f[x][i]!=0){
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}
inline void build(int l,int r,int rt){
    T[rt].minn=inf;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1); 
}
inline void insert(int l,int r,int rt){
    if(l>y||r<x) return;
    if(l>=x&&r<=y){
        T[rt].minn=min(T[rt].minn,val);
        return ;
    }
    int mid=(l+r)>>1;
    insert(l,mid,rt<<1);
    insert(mid+1,r,rt<<1|1);
}
inline void change(int u,int v,int vl){
    int t=lca(u,v);
    val=dis[u]+vl+dis[v];
    while(top[u]!=top[t]){
        x=dfn[top[u]];y=dfn[u];
        insert(1,n,1);u=f[top[u]][0];
    }
    if(u!=t) x=dfn[t]+1,y=dfn[u],insert(1,n,1);
    while(top[v]!=top[t]){
        x=dfn[top[v]],y=dfn[v];
        insert(1,n,1);v=f[top[v]][0];
    }
    if(v!=t) x=dfn[t]+1,y=dfn[v],insert(1,n,1); 
}
inline void query(int l,int r,int rt){
    ans=min(ans,T[rt].minn);
    if(l==r) return;
    int mid=(l+r)>>1;
    if(x<=mid) query(l,mid,rt<<1);
    else query(mid+1,r,rt<<1|1);
}
int main(){
    //freopen("All.in","r",stdin);
    //freoepn("All.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=m;i++){
        u[i]=read();v[i]=read();l[i]=read();is[i]=read();
        if(is[i]) insertt(u[i],v[i],l[i]),insertt(v[i],u[i],l[i]);
    }
    dfs1(1,0);dfs2(1,0);
    getanser();
    build(1,n,1);
    for(int i=1;i<=m;i++){
        if(!is[i]) change(u[i],v[i],l[i]);
    }
    for(int i=2;i<n;i++){
        //cout<<dfn[i]<<endl;
        x=dfn[i];ans=inf;query(1,n,1);
        if(ans==inf) printf("-1 ");
        else printf("%d ",ans-dis[i]);
    }
    if(n!=1){
        x=dfn[n];ans=inf;query(1,n,1);
        if(ans==inf) printf("-1");
        else printf("%d",ans-dis[n]);
    }
    return 0;
}

  

posted @ 2018-07-22 13:23  zhangenming  阅读(222)  评论(0编辑  收藏  举报