各种姿势过【模板】单源最短路径(标准版)

洛谷P4779

板子,堆优化+标记数组优化

spfa魔改

迪杰斯特拉堆优化+判断

zkw线段树优化

线段树优化

树状数组优化

左偏树优化,

左偏树+回收节点优化

小根堆优化


 

加一个zkw线段树优化的板子---虽然我看不懂= = 

尝试了下洛谷里大佬说的几个Ac的方法

感觉都差不多

用时: 1487ms / 内存: 13272KB------------------------------------迪杰斯特拉堆优化+标记数组
用时: 1525ms / 内存: 12656KB------------------------------------魔改spfa(迪杰斯特拉+spfa的队列数组)
用时: 1501ms / 内存: 12960KB------------------------------------迪杰斯特拉堆优化+判断

第1,2个都需要额外开一个n的数组,3不需要

O2优化之后就都300ms左右了(话说手写堆的是真的强)

用时: 365ms / 内存: 13012KB

用时: 329ms / 内存: 12704KB

用时: 335ms / 内存: 13376KB

 

板子,堆优化+标记数组优化

#include 
using namespace std;
typedef long long ll;
vector > E[200005];
ll dis[100005];
bool vis[100005];
void init(ll n,ll m)
{
    for(ll i=0;i<=n;i++)dis[i] = 1e18;
    for(ll i=0;i<=m;i++)E[i].clear();
}
void dijstkra(ll s){
    priority_queue > Q;
    Q.push(make_pair(0,s));dis[s] = 0;
    while(!Q.empty())
    {
        ll now = Q.top().second;
        Q.pop();
        if(vis[now])continue;
        vis[now] = 1;
        for(ll i=0;idis[now]+x)
            {
                dis[v] = dis[now]+x;
                Q.push(make_pair(-dis[v],v));
            }
        }
    }
}
int main() {

    ll n,m,s;
    while(~scanf("%lld%lld%lld",&n,&m,&s))
    {
        init(n,m);
        for(ll i=0;i

 

spfa魔改

void dijstkra(ll s){
    priority_queue > Q;
    Q.push(make_pair(0,s));dis[s] = 0;
    while(!Q.empty())
    {
        ll now = Q.top().second;
        Q.pop();
        in[now] = 0;
        for(ll i=0;idis[now]+x)
            {
                dis[v] = dis[now]+x;
                if(!in[v])
                    Q.push(make_pair(-dis[v],v)),in[v] = 1;
            }
        }
    }
}

 

迪杰斯特拉堆优化+判断

void dijstkra(ll s){
    priority_queue > Q;
    Q.push(make_pair(0,s));dis[s] = 0;
    while(!Q.empty())
    {
        ll now = Q.top().second;
        ll t = -Q.top().first;
        Q.pop();
        if(t>dis[now])continue;
        for(ll i=0;idis[now]+x)
            {
                dis[v] = dis[now]+x;
                Q.push(make_pair(-dis[v],v));
            }
        }
    }
}

 

zkw线段树优化

#include
#define re register int
using namespace std;
const int N=1e5+5,M=5e5+5,inf=-1u>>1,oo=inf>>1;
typedef int arr[N];
struct edges{int nx,to,w;}e[M<<1];
int n,m,s,tot;arr fi,dis;
inline void add(re u,re v,re w){e[++tot]=(edges){fi[u],v,w};fi[u]=tot;}
namespace zkw{
    int tr[N<<2],sgt=1;
    inline void build(re n){while(sgt<=n)sgt<<=1;--sgt;tr[0]=N-1;}
    inline void clr(){for(int i=1;i<=(sgt<<1)+1;i++)tr[i]=0;}
    inline int cmp(const re&a,const re&b){return dis[a]w;i>>=1)tr[i]=x;dis[x]=w;}
    inline void del(re x){tr[x+=sgt]=0;x>>=1;while(x)tr[x]=cmp(tr[x<<1],tr[x<<1|1]),x>>=1;}
}
using namespace zkw;
inline void dij(re s,re*dis){
    for(int i=0;i<=n;i++)dis[i]=inf;clr();Mdy(s,0);
    for(int k = 1;k<=n;k++){
        re u=tr[1];del(u);
        for(re i=fi[u],v;i;i=e[i].nx)
            if(dis[v=e[i].to]>dis[u]+e[i].w)
                Mdy(v,dis[u]+e[i].w);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&s);
    build(n);re u,v,w;
    for(int i=1;i<=m;i++)scanf("%d%d%d",&u,&v,&w),add(u,v,w);
    dij(s,dis);
    for(int i=1;i<=n;i++)
        printf("%d%c",dis[i],i==n?'\n':' ');
    return 0;
}

 

 

以下是写着玩的代码,自个儿乐一乐

 

自己写的

线段树优化

,开o2,600ms,不开1000ms

#include
using namespace std;
const int maxn=200000+100,inf = 0x3f3f3f3f;
typedef long long ll;
typedef pair,int> Edge;/// to,val,next
int dis[maxn],head[maxn],cnt,n,m,s;
Edge E[maxn];
bool vis[maxn];
void init(){memset(head,-1,sizeof(head)),cnt = 0;}
void add(int u,int v,int w){
    E[cnt] = {{v,w},head[u]};
    head[u] = cnt++;
}
struct node{
    int l,r;
    pair val;
}tree[maxn<<2];
void push_up(int x){
    tree[x].val = min(tree[x<<1].val,tree[x<<1|1].val);
}
void build(int x,int l,int r){
    tree[x].l = l,tree[x].r = r;
    if(l == r)
        tree[x].val = {dis[l],l};
    else{
        int mid = (l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        push_up(x);
    }
}
void updata(int x,int pos,int val){
    int L = tree[x].l,R = tree[x].r;
    if(L == R && L == pos)
        tree[x].val = {val,L};
    else{
        int mid = (L+R)>>1;
        updata(pos<=mid?x<<1:x<<1|1,pos,val);
        push_up(x);
    }
}
pair query(int x,int l,int r){
    int L = tree[x].l,R = tree[x].r;
    if(l<=L && R<=r)
        return tree[x].val;
    else{
        int mid = (L+R)>>1;
        pair ans = {inf,inf};
        if(l <= mid)ans = min(ans,query(x<<1,l,r));
        if(r > mid )ans = min(ans,query(x<<1|1,l,r));
        return ans;
    }
}
void dijstkra(int s){
    for(int i=1;i<=n;i++)dis[i] = inf;
    dis[s] = 0;
    build(1,1,n);
    for(int k = 1;k<=n;k++){
        int u = query(1,1,n).second;
        vis[u] = 1;
        updata(1,u,inf);
        for(int i = head[u];~i;i = E[i].second)
            if(!vis[E[i].first.first] && dis[E[i].first.first]>dis[u]+E[i].first.second)
                updata(1,E[i].first.first,dis[u]+E[i].first.second),dis[E[i].first.first] = dis[u]+E[i].first.second;
    }
}
int main(){
    init();
    scanf("%d%d%d",&n,&m,&s);
    int u,v,w;
    while(m--)scanf("%d%d%d",&u,&v,&w),add(u,v,w);
    dijstkra(s);
    for(int i=1;i<=n;i++)
        printf("%d%c",dis[i],i==n?'\n':' ');
    return 0;
}

 

树状数组优化

复杂度多乘以个log也就是说复杂度是n*logn*longn,开o2,800ms,不开3000ms

#include
#define to first.first
#define W first.second
#define next second
using namespace std;
const int maxn=200000+100,inf = 0x3f3f3f3f;
typedef long long ll;
typedef pair,int> Edge;/// to,w,next
int head[maxn],cnt,n,m,s,ans[maxn];
pair dis[maxn],tree[maxn];
Edge E[maxn];
bool vis[maxn];
void init(){memset(head,-1,sizeof(head)),cnt = 0;}
void add(int u,int v,int w){
    E[cnt] = make_pair(make_pair(v,w),head[u]);
    head[u] = cnt++;
}
void updata(int pos){
    while(pos<=n){
        tree[pos] = dis[pos];
        int lpos = pos&-pos;
        for(int i=1;i query(int l,int r){
    pair ans = {inf,inf};
    while(r >= l){
        ans = min(ans,dis[r--]);
        while(r - (r&-r) >= l)
            ans = min(ans,tree[r]),r -= r&-r;
    }
    return ans;
}
void dijstkra(int s){
    for(int i=1;i<=n;i++)dis[i] = {inf,i},updata(i),ans[i]=inf;
    dis[s] = {0,s},updata(s);
    for(int k = 1;k<=n;k++){
        int u = query(1,n).second;
        ans[u] = dis[u].first;
        vis[u] = 1;
        dis[u].first = inf;
        updata(u);
        for(int i = head[u];~i;i = E[i].next)
            if(!vis[E[i].to] && dis[E[i].to].first>ans[u]+E[i].W)
                dis[E[i].to].first = ans[u]+E[i].W,updata(E[i].to);
    }
}
int main(){
    init();
    scanf("%d%d%d",&n,&m,&s);
    int u,v,w;
    while(m--)scanf("%d%d%d",&u,&v,&w),add(u,v,w);
    dijstkra(s);
    for(int i=1;i<=n;i++)
        printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}

 

左偏树优化,

笑,584ms,空间也是12MB,当然,看你开的数组大小了,不能自适应

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int head[maxn],to[maxn*4],wt[maxn*4],nex[maxn*4],cnt = 1;
ll ans[maxn];
int n,m,s;
void add(int u,int v,int w){
    to[cnt] = v;
    nex[cnt] = head[u];
    wt   [cnt] = w;
    head[u] = cnt++;
}
int l[maxn*2],r[maxn*2],dis[maxn*2],tot,root;
pair val[maxn*2];
int Merge(int x,int y){
    if(!x||!y)return x+y;
    if(val[x]>val[y])swap(x,y);
    r[x] = Merge(r[x],y);
    if(dis[l[x]]ans[u])continue;
        for(int i=head[u];i;i=nex[i]){
            if(ans[to[i]]>ans[u]+wt[i]){
                ans[to[i]] = ans[u]+wt[i];
                val[++tot] = make_pair(ans[to[i]],to[i]);
                root = Merge(tot,root);
            }
        }
    }
}
int main() {
    scanf("%d%d%d",&n,&m,&s);
    while(m--){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    dijstkra(s);
    for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
    return 0;
}

 

左偏树+回收节点优化

其实很简单,删掉的点就不用了,拿一个栈(数组模拟即可)存一下,

每次新加节点的时候看看栈空不空,不空就从栈里拿点就好

这样优化内存到了9MB左右,

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int head[maxn],to[maxn*4],wt[maxn*4],nex[maxn*4],stk[maxn],top,cnt = 1;
ll ans[maxn];
int n,m,s;
void add(int u,int v,int w){
    to[cnt] = v;
    nex[cnt] = head[u];
    wt   [cnt] = w;
    head[u] = cnt++;
}
int l[maxn],r[maxn],dis[maxn],tot,root;
pair val[maxn];
int Merge(int x,int y){
    if(!x||!y)return x+y;
    if(val[x]>val[y])swap(x,y);
    r[x] = Merge(r[x],y);
    if(dis[l[x]] v){
    if(top)
        return val[stk[--top]] = v,stk[top];
    return val[++tot] = v,tot;
}
void dijstkra(int s){
    for(int i=1;i<=n;i++)ans[i] = 1e15;
    ans[s] = 0;
    root = Merge(root,push(make_pair(0,s)));
    while(root){
        int u = val[root].second;
        ll w = val[root].first;
        del();
        if(w>ans[u])continue;
        for(int i=head[u];i;i=nex[i]){
            if(ans[to[i]]>ans[u]+wt[i]){
                ans[to[i]] = ans[u]+wt[i];
                root = Merge(root,push(make_pair(ans[to[i]],to[i])));
            }
        }
    }
}
int main() {
    scanf("%d%d%d",&n,&m,&s);
    while(m--){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    dijstkra(s);
    for(int i=1;i<=n;i++)printf("%lld%c",ans[i],i==n?'\n':' ');
    //printf("%d\n",tot);
    return 0;
}

 

 

 

小根堆优化

(相当于手写优先队列)开o2 400ms,不开700ms

// luogu-judger-enable-o2
#include 
using namespace std;
typedef long long ll;
vector > E[200005];
ll dis[100005];
bool vis[100005];
void init(ll n,ll m)
{
    for(ll i=0;i<=n;i++)dis[i] = 1e18;
    for(ll i=0;i<=m;i++)E[i].clear();
}
struct node{
    ll pos,w;
}heap[100007<<4];
int tot;//small heap
void Insert(node data,int pos = tot+1){
    heap[++tot] = data;
    while(pos != 1 && heap[pos].w>1].w)
        swap(heap[pos],heap[pos>>1]),pos>>=1;
}
void del(int pos = 1){
    if(!tot)return;
    heap[pos] = heap[tot--];
    while(true){
        int tpos = pos;
        if((pos<<1)<=tot && heap[tpos].w>heap[pos<<1].w)tpos = pos<<1;
        if((pos<<1|1)<=tot && heap[tpos].w>heap[pos<<1|1].w)tpos = pos<<1|1;
        if(tpos == pos)break;
        swap(heap[pos],heap[tpos]),pos = tpos;
    }
}
void dijstkra(ll s){
    Insert(node{s,0});
    dis[s] = 0;
    while(tot)
    {
        ll now = heap[1].pos;
        del();
        if(vis[now])continue;
        vis[now] = 1;
        for(ll i=0;idis[now]+x)
            {
                dis[v] = dis[now]+x;
                Insert(node{v,dis[v]});
            }
        }
    }
}
int main() {
    ll n,m,s;
    while(~scanf("%lld%lld%lld",&n,&m,&s))
    {
        init(n,m);
        for(ll i=0;i

 

你可能感兴趣的:(模板类(什么,这也是模板))