堆优化/zkw线段树优化 dijkstra

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int MAXM = 200005;
inline void read(int &num)
{
    char ch; int flag=1;
    while(!isdigit(ch=getchar()))if(ch=='-')flag=-flag;
    for(num=ch-'0';isdigit(ch=getchar());num=num*10+ch-'0');
}
int N, M, S;

int fir[MAXN], to[MAXM], nxt[MAXM], w[MAXM], cnt;
inline void Add(int u, int v, int wt)
{
    to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; w[cnt] = wt;
}

int dis[MAXN];
bool vis[MAXN];
#define pii pair<int,int>
#define mp make_pair
priority_queue<pii, vector<pii>, greater<pii> >q;
inline void Dijkstra_heap(int s)
{
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    dis[s] = 0; q.push(mp(0, s));
    while(!q.empty())
    {
        int u = q.top().second; q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = fir[u]; i; i = nxt[i])
            if(!vis[to[i]] && dis[to[i]] > dis[u] + w[i])
                q.push(mp(dis[to[i]]=dis[u] + w[i], to[i]));
    }
}

int Min[MAXN<<2], hp[MAXN], bit;

inline void Modify(int x) { for(x>>=1; x; x>>=1) Min[x] = (hp[Min[x<<1]] < hp[Min[x<<1|1]]) ? Min[x<<1] : Min[x<<1|1]; }
inline void Build() { for(bit = 1; bit <= N+1; bit<<=1); }
inline void Update(int x, int dist) { hp[x] = dist; Modify(bit+x); }

inline void Dijkstra_segment_tree(int s)
{
	memset(dis, -1, sizeof dis);
	memset(hp, 0x3f, sizeof hp);
	Build(); hp[s] = 0;
	for(int i = 1; i <= N; i++) Min[bit+i] = i, Update(i, hp[i]);
	for(int i = 1; i <= N; i++)
	{
		int u = Min[1];
		dis[u] = hp[u];
		Update(u, 0x3f3f3f3f);
		for(int j = fir[u]; j; j = nxt[j])
			if(dis[to[j]] == -1 && hp[to[j]] > dis[u] + w[j])
				Update(to[j], dis[u] + w[j]);
	}
}

int main ()
{
    int x, y, z, S;
    read(N), read(M), read(S);
    for(int i = 1; i <= M; i++)
        read(x), read(y), read(z), Add(x, y, z);
    Dijkstra_heap(S);
    //Dijkstra_segment_tree(S);
	for(int i = 1; i < N; i++) printf("%d ", dis[i]);
    printf("%d
", dis[N]);
}

CAUTION!CAUTION!注意堆优化dij不能这么写:!!!!

int dis[MAXN];
bool vis[MAXN];
struct cmp
{
    bool operator ()(int a, int b) //重载优先级低的(1:a优先级低 0:b优先级低)
    {
        return dis[a] > dis[b]; //此处有问题
    }
};
priority_queue<int, vector<int>, cmp>q;
void Dijkstra_heap(int s)
{
    memset(dis, 0x7f, sizeof dis);
    memset(vis, 0, sizeof vis);
    dis[s] = 0; q.push(s);
    while(!q.empty())
    {
        int u = q.top(); q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = fir[u]; i; i = nxt[i])
            if(!vis[to[i]] && dis[to[i]] > dis[u] + w[i])
            {
                dis[to[i]] = dis[u] + w[i];
                q.push(to[i]);
            }
    }
}

由于优先队列的有序性是取决于插入的位置,当dis值在外面被修改,队列的元素顺序不会改变,于是就失去了有序性。在luogu的最短路模板题(传送门)就会WA。不过有的数据水的还是能过许多点。

原文地址:https://www.cnblogs.com/Orz-IE/p/12039500.html