k短路

有一个A*写法?
然后我并不是很会…应该就是直接搜吧?
正常写法是..先从终点建反向边的最短路树。
对于任意一条不在最短路树上的边,
定义其权值 w=Disv+wDisu 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 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值