传送门:bzoj4912
题解
最短路。
发现从点到点时的代价是不确定的,而从边到边的代价是一定的,所以将边转化为点,点权 v a l i val_i vali为全图中的边权,设所有以1为起点的边 d i s i = v a l i dis_i=val_i disi=vali,建图连边跑最短路后,对于点 x x x,求出所有指向 x x x的边的 m i n ( d i s i ) min(dis_i) min(disi)就得到了根到 x x x的最短路。
新图中点 x x x到点 y y y的花费即为 v a l y + val_y+ valy+trie树中 L C A ( d x , d y ) LCA(d_x,d_y) LCA(dx,dy)的深度。
代表某条边的点会和所有其他与这条边端点有交集的边之间连边,最坏情况连边多达 n 2 n^2 n2条(菊花图)。
考虑优化连边:
将
t
r
i
e
trie
trie树上的点按dfs序排序后能够发现
l
c
p
(
d
x
,
d
y
)
lcp(d_x,d_y)
lcp(dx,dy)具有与后缀数组类似的性质:设
l
e
n
x
=
l
c
p
(
d
x
,
d
x
+
1
)
len_x=lcp(d_x,d_{x+1})
lenx=lcp(dx,dx+1),则
l
c
p
(
d
x
,
d
y
)
=
m
i
n
(
l
e
n
x
,
l
e
n
x
+
1
,
.
.
,
l
e
n
y
−
1
)
lcp(d_x,d_y)=min(len_{x},len_{x+1},..,len_{y-1})
lcp(dx,dy)=min(lenx,lenx+1,..,leny−1)。而
l
c
p
lcp
lcp的取值也只有
k
k
k种。
于是对于原图中每个点相关的边,将 d i d_i di按dfs排序,枚举分界点 x x x,所有标号 ≤ x \leq x ≤x到标号 ≥ x \geq x ≥x的点之间的距离必然不超过 l e n x len_x lenx,所以分别拆成前缀入度出度和后缀入度出度。
点数是 O ( m ) O(m) O(m)的复杂度 O ( m l o g m ) O(mlogm) O(mlogm)
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+100,M=2e6+100,inf=0x7f7f7f7f;
int n,m,K,tk,q[N],df[N],len,val[N*10],dis[N*10];
int head[N*10],to[M],nxt[M],w[M],tot;
int xi[N],xt[N],yi[N],yt[N],cnt;
char buf[N];
inline char gc()
{
static int p1=0,p2=0;
if(p1==p2) p1=0,p2=fread(buf,1,N,stdin);
if(p1==p2) return EOF;
return buf[p1++];
}
char cp,OS[100];
inline void rd(int &x)
{
cp=gc();x=0;
for(;!isdigit(cp);cp=gc());
for(;isdigit(cp);cp=gc()) x=(x<<3)+(x<<1)+(cp^48);
}
char wbuf[N];int p3;
inline void wchar(char x)
{
if(p3==N) fwrite(wbuf,1,N,stdout),p3=0;
wbuf[p3++]=x;
}
inline void ot(int x)
{
int re=0;
for(;(!re)||(x);x/=10) OS[++re]='0'+x%10;
OS[0]='\n';
for(;~re;--re) wchar(OS[re]);
}
struct E{
int a,b,c,d;
inline void ini(){rd(a);rd(b);rd(c);rd(d);}
}e[N];
struct Dr{
int head[N],to[N],nxt[N],tot;
inline void itia(){memset(head,0,sizeof(int)*(n+1));tot=0;}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
}di,dt;
struct Trie{
int head[N],to[N],nxt[N],tot;
int son[N],top[N],f[N],dep[N],sz[N],dfn;
inline void itia(){memset(head,0,sizeof(int)*(K+1));tot=dfn=0;}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void dfs(int x)
{
sz[x]=1;son[x]=0;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];dep[j]=dep[x]+1;f[j]=x;dfs(j);
sz[x]+=sz[j];if(sz[son[x]]<sz[j]) son[x]=j;
}
}
void dfss(int x,int tpo)
{
top[x]=tpo;df[x]=++dfn;
if(!son[x]) return;
dfss(son[x],tpo);
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==son[x]) continue;
dfss(j,j);
}
}
inline void build()
{
int i,x,y,z;
for(i=1;i<K;++i) {rd(x);rd(y);rd(z);lk(x,y);}
dfs(1);dfss(1,1);
}
inline int LCA(int x,int y)
{
for(;top[x]!=top[y];x=f[top[x]])
if(dep[top[x]]<dep[top[y]]) swap(x,y);
return min(dep[x],dep[y]);
}
}trie;
inline void lk(int u,int v,int vv)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;}
inline bool cmp(const int&x,const int&y){return df[e[abs(x)].d]<df[e[abs(y)].d];}
inline void mk(int x)
{
if((!di.head[x])||(!dt.head[x])) return;
int i,j;len=0;
for(i=di.head[x];i;i=di.nxt[i]) q[++len]=di.to[i];
for(i=dt.head[x];i;i=dt.nxt[i]) q[++len]=-dt.to[i];
sort(q+1,q+len+1,cmp);
for(i=1;i<=len;++i){
xi[i]=++cnt;xt[i]=++cnt;yi[i]=++cnt;yt[i]=++cnt;
if(i>1){
lk(xi[i-1],xi[i],0);lk(xt[i-1],xt[i],0);
lk(yi[i],yi[i-1],0);lk(yt[i],yt[i-1],0);
}
if(q[i]>0) {lk(q[i],xi[i],0);lk(q[i],yi[i],0);}
else {q[i]=-q[i];lk(xt[i],q[i],0);lk(yt[i],q[i],0);}
}
for(i=1;i<len;++i){
j=trie.LCA(e[q[i]].d,e[q[i+1]].d);
lk(xi[i],xt[i+1],j);lk(yi[i+1],yt[i],j);
}
}
struct Pr{
int id,v;
bool operator<(const Pr&ky)const{
return ky.v<v;
}
}tp;
priority_queue<Pr>que;
inline void spfa()
{
memset(dis,0x7f,sizeof(dis));
int i,j,x;
for(i=1;i<=m;++i) if(e[i].a==1){dis[i]=val[i];que.push((Pr){i,dis[i]});}
for(;que.size();){
tp=que.top();que.pop();
x=tp.id;if(dis[x]!=tp.v) continue;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(dis[j]<=dis[x]+val[j]+w[i]) continue;
dis[j]=dis[x]+val[j]+w[i];que.push((Pr){j,dis[j]});
}
}
}
inline void sol()
{
int i,j,x,y,z;
memset(head,0,sizeof(int)*(cnt+1));memset(val,0,sizeof(int)*(m+1));
tot=0;trie.itia();di.itia();dt.itia();
rd(n);rd(m);rd(K);cnt=m;
for(i=1;i<=m;++i){
e[i].ini();val[i]=e[i].c;
dt.lk(e[i].a,i);di.lk(e[i].b,i);
}
trie.build();
for(i=1;i<=n;++i) mk(i);
spfa();
for(i=2;i<=n;++i){
for(z=inf,j=di.head[i];j;j=di.nxt[j])
z=min(z,dis[di.to[j]]);
ot(z);
}
}
int main(){
for(rd(tk);tk;--tk) sol();
if(p3) fwrite(wbuf,1,p3,stdout);
return 0;
}