BZOJ 3694 最短路
3694: 最短路
Time Limit: 5 Sec Memory Limit: 256 MBSubmit: 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
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; }