有一个A*写法?
然后我并不是很会…应该就是直接搜吧?
正常写法是..先从终点建反向边的最短路树。
对于任意一条不在最短路树上的边,
定义其权值
w=Disv+w−Disu
w
=
D
i
s
v
+
w
−
D
i
s
u
,
即多绕的路程长度。
考虑取一个不在最短路树上的边的序列(可能有重复),
那么应满足对于相邻的两条边,
满足
vi
v
i
是
ui
u
i
在最短路树上的孩子或
vi=ui
v
i
=
u
i
,
这样才能在不走这些边的情况下走原先的最短路,
其中显然有
v0=s
v
0
=
s
。
那么我只要对于某个点
x
x
,
求出及
x
x
<script type="math/tex" id="MathJax-Element-8">x</script>祖先形成的有序边表,
就可以用优先队列瞎搞求答案了?
好像是这样的…但是有序边表并不好搞
事实上弄个可持久化左偏树合并一下就可以了((
Code
#include<bits/stdc++.h>
using namespace std;
#define Death Komachi
#define Uni All Right
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;++i)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;--i)
#define LREP(i,a) for(int i=Head[a];i;i=Next[i])
#define M 200004
#define LL long long
void Rd(int &x){
static char c;x=0;
while((c=getchar())<48);
do x=(x<<3)+(x<<1)+(c^48);
while((c=getchar())>47);
}
int n,m,s,t,K;
int V[M],W[M],Next[M],Head[M],tot;
void Add_Edge(int u,int v,int w){
Next[++tot]=Head[u],V[Head[u]=tot]=v,W[tot]=w;
}
struct Node{
int x;LL w;
bool operator <(const Node &_)const{
return w>_.w;
}
};
int D[M],E[M],Tail[M],Pre[M];
LL Dis[M],Val[M];
priority_queue<Node>Q;
inline bool chkmin(LL &a,const LL &b){return b<a?a=b,1:0;}
int Rt[M];
static const int MX=M*30;
int Ch[MX][2],Ht[MX],ID[MX],trp;
void Build(int *A,int &x,int n){
//这是一个线性的建堆...相关资料可以在网上找(反正就是线性的
if(!n)return;
x=trp+1;
REP(i,1,n+1){
int j=trp+i,nt=i<<1;
Ch[j][0]=nt<=n?trp+nt:0;nt++;
Ch[j][1]=nt<=n?trp+nt:0;
ID[j]=E[i];
}
DREP(i,n,0){
int x=trp+i,a,b;
Ht[x]=Ht[Ch[x][0]]+1;
while(a=Ch[x][0]){
if((b=Ch[x][1]) && Val[ID[b]]<Val[ID[a]])swap(a,b);
if(Val[ID[a]]<Val[ID[x]])swap(ID[x],ID[a]),x=a;
else break;
}
}
trp+=n;
}
//左偏树合并
int Merge(int p,int q){
if(!p||!q)return p|q;
if(Val[ID[p]]>Val[ID[q]])swap(p,q);
int x=++trp,&l=Ch[x][0],&r=Ch[x][1];
ID[x]=ID[p];
l=Ch[p][0];
r=Merge(Ch[p][1],q);
if(Ht[l]<Ht[r])swap(l,r);
Ht[x]=Ht[l]+1;
return x;
}
void Dij(){
memset(Dis,63,sizeof(Dis));
Q.push((Node){t,Dis[t]=0});
int r=0;
while(!Q.empty()){
int x=Q.top().x,y;
LL w=Q.top().w;Q.pop();
if(w!=Dis[x])continue;
D[++r]=x;
LREP(i,x)if(chkmin(Dis[y=V[i]],w+W[i]))
Q.push((Node){y,Dis[y]}),Pre[y]=i^1;
}
int id=0;
REP(i,1,r+1){
int x=D[i],y,p=0;
LREP(j,x+n)if(j!=Pre[x])
Val[id]=W[j]+Dis[Tail[id]=V[j]]-Dis[x],E[++p]=id++;
Build(E,Rt[x],p);
if(x!=t)Rt[x]=Merge(Rt[x],Rt[V[Pre[x]]]);
}
}
void Work(){
if(!(--K)){printf("%lld\n",Dis[s]);return;}
if(Rt[s])Q.push((Node){Rt[s],Dis[s]+Val[ID[Rt[s]]]});
while(!Q.empty()){
int x=Q.top().x;
LL w=Q.top().w;Q.pop();
if(!(--K)){printf("%lld\n",w);return;}
#define AddNode(a) if(a)Q.push((Node){a,w+Val[ID[a]]});
AddNode(Rt[Tail[ID[x]]]);
//加入这条边后 再加入其它边的情况
w-=Val[ID[x]];
AddNode(Ch[x][0]);
AddNode(Ch[x][1]);
//继续从该点选择比这条边大的其它边的情况
}
puts("-1");
}
int main(){
Rd(n),Rd(m);
tot=1;
while(m--){
int u,v,w;
Rd(u),Rd(v),Rd(w);
Add_Edge(v,u,w);
Add_Edge(u+n,v,w);
}
Rd(s),Rd(t),Rd(K);
if(s==t)K++;
Dij();
Work();
return 0;
}
然后是后面那个第k长路的题…
#include<bits/stdc++.h>
using namespace std;
#define Death Komachi
#define Uni All Right
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;++i)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;--i)
#define LREP(i,a) for(int i=Head[a];i;i=Next[i])
#define M 600004
#define MP 2000004
#define LL long long
#define INF 0xc0c0c0c0
int n,m,s,t,K;
int V[MP],W[MP],Next[MP],Head[M],tot;
int Deg[M];
void Add_Edge(int u,int v,int w){
Next[++tot]=Head[u],V[Head[u]=tot]=v,W[tot]=w;
}
void AddEdge(int u,int v,int w){
// cerr<<u<<' '<<v<<' '<<w<<endl;
Add_Edge(v,u,w),++Deg[u];
Add_Edge(u+n,v,w);
}
struct Node{
int x,w;
bool operator <(const Node &_)const{
return w<_.w;
}
};
int D[M],E[M],Tail[M],Pre[M];
int Dis[M],Val[M];
priority_queue<Node>Q;
inline bool chkmax(int &a,const int &b){return a<b?a=b,1:0;}
int Rt[M];
static const int MX=M*60;
int Ch[MX][2],Ht[MX],ID[MX],trp;
void Build(int *A,int &x,int n){
if(!n){x=0;return;}
x=trp+1;
REP(i,1,n+1){
int j=trp+i,nt=i<<1;
Ch[j][0]=nt<=n?trp+nt:0;nt++;
Ch[j][1]=nt<=n?trp+nt:0;
ID[j]=E[i];
}
DREP(i,n,0){
int x=trp+i,a,b;
Ht[x]=Ht[Ch[x][0]]+1;
while(a=Ch[x][0]){
if((b=Ch[x][1]) && Val[ID[b]]>Val[ID[a]])swap(a,b);
if(Val[ID[a]]>Val[ID[x]])swap(ID[x],ID[a]),x=a;
else break;
}
}
trp+=n;
}
int Merge(int p,int q){
if(!p||!q)return p|q;
if(Val[ID[p]]<Val[ID[q]])swap(p,q);
int x=++trp,&l=Ch[x][0],&r=Ch[x][1];
ID[x]=ID[p];
l=Ch[p][0];
r=Merge(Ch[p][1],q);
if(Ht[l]<Ht[r])swap(l,r);
Ht[x]=Ht[l]+1;
return x;
}
void Dij(){
int l=1,r=0;
Dis[t]=0;
REP(i,1,n+1)if(!Deg[i])D[++r]=i;
while(l<=r){
int x=D[l++],y;
LREP(i,x){
if(chkmax(Dis[y=V[i]],Dis[x]+W[i]))Pre[y]=i^1;
if(!(--Deg[y]))D[++r]=y;
}
}
int id=0;
REP(i,1,r+1){
int x=D[i],y,p=0;
if(Dis[x]==INF)continue;
LREP(j,x+n){
if(j!=Pre[x])
Val[id]=W[j]+Dis[Tail[id]=V[j]]-Dis[x],E[++p]=id++;
}
// cerr<<i<<":"<<endl;
// REP(j,0,p)cerr<<Val[E[j]]<<' '<<Tail[E[j]]<<endl;
Build(E,Rt[x],p);
if(x!=t)Rt[x]=Merge(Rt[x],Rt[V[Pre[x]]]);//cerr<<V[Pre[x]]<<' '<<x<<' '<<W[Pre[x]]<<endl;
}
}
void Work(){
while(!Q.empty())Q.pop();
if(!(--K)){printf("%d\n",Dis[s]);return;}
if(Rt[s])Q.push((Node){Rt[s],Dis[s]+Val[ID[Rt[s]]]});
while(!Q.empty()){
int x=Q.top().x;
int w=Q.top().w;Q.pop();
// cerr<<w<<endl;
if(!(--K)){printf("%d\n",w);return;}
#define AddNode(a) if(a)Q.push((Node){a,w+Val[ID[a]]});
AddNode(Rt[Tail[ID[x]]]);
w-=Val[ID[x]];
AddNode(Ch[x][0]);
AddNode(Ch[x][1]);
}
puts("-1");
}
int T;
int main(){
scanf("%d",&T);
while(T--){
trp=0,tot=1;
scanf("%d%d",&m,&K);
n=m*2+2;
s=n-1,t=n;
memset(Pre,0,n+1<<2);
memset(Deg,0,n+1<<2);
memset(Dis,192,n+1<<2);
int C[2],c;
REP(i,1,m+1){
scanf("%d%d%d",&C[0],&C[1],&c);
if(i!=1){
AddEdge(i-1,i,0);
AddEdge(i-1+m,i+m,0);
AddEdge(i-1,i+c*m,C[0]);
AddEdge(i-1+m,i+c*m,C[1]);
}
else AddEdge(s,i,0),AddEdge(s,i+c*m,C[0]);
}
AddEdge(m,t,0);
AddEdge(m+m,t,0);
Dij();
Work();
memset(Head,0,n+1<<3);
}
return 0;
}