luogu 2483 K短路 (可持久化左偏树)
题面:
题目大意:给你一张有向图,求1到n的第k短路
$K$短路模板题
假设整个图的边集为$G$
首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$
那么每个点沿着树边走到点$n$,它对于答案的贡献为0
我们加入一条非树边,它对于答案的贡献就是$delta(u,v)=dis[v]+e(u,v)-dis[u]$,即如果选择了这条边,这条路径的长度就会增加$delta(u,v)$
那么一条路径$p$的总长度就是$dis_{min}+\sum\limits_{e\in p,e\in G-T} delta(e)$
我们现在要求出前$K$条总长度最小的路径长度,(即使在这道题里我们不知道K是多少)
我们首先向一个堆中加入一条非树边,然后依次拓展,拓展的过程是这样的:
每次从堆中取出一条边集$p$,有两种情况
1.把末尾的边替换成,这条边原来所在的边集里,边权大于等于它的一条边
2.对于末尾这条边的终点$v$,在最短路树的所有祖先中,所能扩展的一条最短的非树边
这样扩展保证了每次新产生的边集贡献$\geq $原来的边集贡献,保证了有序性
且每次都选择最短的边集,保证了同一种边集不会重复讨论
第二个操作需要找出最小的后继状态,而后继状态可能很多,想办法用数据结构维护
在最短路树上每个点都维护反向非树边的集合,那么子节点也要包含父节点的集合,需要可持久化
而对于第一个操作,我们需要一个有序表来扩展,所以要用到堆之类的东西
可持久化可并堆!
无非就是$merge$里每次合并都新建节点罢了
第一个操作就是把最后一条边换成这条边在堆中的左右儿子
第二个操作直接取堆顶即可
这也是类似于普通$dijkstra$最短路的扩展过程
1 #include <queue> 2 #include <cmath> 3 #include <vector> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #define N1 5010 8 #define M1 200010 9 #define S1 N1<<8 10 #define ll long long 11 #define dd double 12 using namespace std; 13 const dd eps=1e-7; 14 15 template <typename _T> void read(_T &ret) 16 { 17 ret=0; _T fh=1; char c=getchar(); 18 while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } 19 while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); } 20 ret=ret*fh; 21 } 22 23 int n,m; 24 struct Edge{ 25 int to[M1<<1],nxt[M1<<1],val[M1<<1],head[N1],cte; dd dis[M1<<1]; 26 void ae(int u,int v,dd d) 27 { 28 cte++; to[cte]=v; nxt[cte]=head[u]; 29 head[u]=cte; dis[cte]=d; 30 } 31 }e; 32 33 34 struct node1{ 35 int x; dd d; 36 node1(int x,dd d):x(x),d(d){} node1(){} 37 friend bool operator < (const node1 &s1,const node1 &s2) 38 { 39 return s1.d>s2.d; 40 } 41 }; 42 43 struct Heap{ 44 int ch[S1][2],h[S1],root0[N1],root1[N1],tot; node1 val[S1]; 45 int merge0(int x,int y) 46 { 47 if(!x||!y) return x+y; 48 if(val[x]<val[y]) swap(x,y); 49 ch[x][1]=merge0(ch[x][1],y); 50 if(h[ch[x][0]]<h[ch[x][1]]) swap(ch[x][0],ch[x][1]); 51 h[x]=h[ch[x][1]]+1; 52 return x; 53 } 54 int merge1(int x,int y) 55 { 56 if(!x||!y) return x+y; 57 if(val[x]<val[y]) swap(x,y); 58 int nx=++tot; val[nx]=val[x]; ch[nx][0]=ch[x][0]; ch[nx][1]=ch[x][1]; h[nx]=h[x]; 59 ch[nx][1]=merge1(ch[x][1],y); 60 if(h[ch[nx][0]]<h[ch[nx][1]]) swap(ch[nx][0],ch[nx][1]); 61 h[nx]=h[ch[nx][1]]+1; 62 return nx; 63 } 64 }h; 65 66 priority_queue<node1>q; 67 int use[N1]; dd dis[N1]; 68 void dijkstra() 69 { 70 node1 k; int x,j,v; 71 q.push(node1(n,0)); dis[n]=0; 72 for(j=1;j<n;j++) dis[j]=666666666; 73 while(!q.empty()) 74 { 75 k=q.top(); q.pop(); x=k.x; 76 if(use[x]) continue; use[x]=1; 77 for(j=e.head[x];j;j=e.nxt[j]) 78 { 79 v=e.to[j]; 80 if(dis[v]-eps>dis[x]+e.dis[j]) 81 { 82 dis[v]=dis[x]+e.dis[j]; 83 q.push(node1(v,dis[v])); 84 } 85 } 86 } 87 } 88 int fa[N1],de; dd la[N1]; 89 void dfs_tree(int x) 90 { 91 int j,v; 92 if(fa[x]) h.root1[x]=h.merge1(h.root1[fa[x]],h.root0[x]); 93 for(j=e.head[x];j;j=e.nxt[j]) 94 { 95 v=e.to[j]; if(!e.val[j]) continue; 96 dfs_tree(v); 97 } 98 } 99 void build_tree() 100 { 101 int i,x,j,v; 102 for(i=1;i<=n;i++) 103 { 104 for(j=e.head[i];j;j=e.nxt[j]) 105 { 106 v=e.to[j]; 107 if(!fa[v]&&fabs(dis[i]+e.dis[j]-dis[v])<eps) 108 e.val[j]^=1, fa[v]=i; 109 } 110 } 111 for(x=1;x<=n;x++) 112 { 113 for(j=e.head[x];j;j=e.nxt[j]) 114 { 115 v=e.to[j]; if(e.val[j]) continue; 116 h.val[++h.tot]=node1(x,dis[x]+e.dis[j]-dis[v]); 117 h.root0[v]=h.merge0(h.root0[v],h.tot); 118 } 119 } 120 } 121 dd E; 122 struct node2{ 123 int x,v; dd d,D; 124 node2(int x,int v,dd d,dd D):x(x),v(v),d(d),D(D){} node2(){} 125 friend bool operator < (const node2 &s1,const node2 &s2) 126 { 127 return s1.D>s2.D; 128 } 129 }; 130 priority_queue<node2>que; 131 132 void debug() 133 { 134 int x=1; 135 while(fa[x]) printf("%d ",fa[x]), x=fa[x]; 136 puts(""); 137 } 138 139 int main() 140 { 141 //freopen("testdata.in","r",stdin); 142 scanf("%d%d%lf",&n,&m,&E); 143 int i,j,k,x,y,v,xx,vv,ans=0; dd d,now,w; 144 for(i=1;i<=m;i++) 145 { 146 read(x), read(y), scanf("%lf",&d); 147 e.ae(y,x,d); 148 } 149 dijkstra(); 150 build_tree(); 151 dfs_tree(n); 152 node2 K; 153 que.push(node2(0,1,0,0)); ans=0; 154 //debug(); 155 while(!que.empty()) 156 { 157 K=que.top(); que.pop(); x=K.x; v=K.v; E-=K.D+dis[1]; 158 //printf("%lf\n",K.D+dis[1]); 159 if(E>-eps) ans++; else break; 160 if(h.root1[v]) 161 { 162 j=h.root1[v]; vv=h.val[j].x; w=h.val[j].d; 163 que.push(node2(j,vv,w,K.D+w)); 164 } 165 if(h.ch[x][0]) 166 { 167 j=h.ch[x][0]; vv=h.val[j].x; w=h.val[j].d; 168 que.push(node2(j,vv,w,K.D-K.d+w)); 169 } 170 if(h.ch[x][1]) 171 { 172 j=h.ch[x][1]; vv=h.val[j].x; w=h.val[j].d; 173 que.push(node2(j,vv,w,K.D-K.d+w)); 174 } 175 } 176 printf("%d\n",ans); 177 return 0; 178 }