Dijkstra求最短路。

这题用普通的手写堆还过不了。。

考虑更新一个堆中的元素时,普通的优先队列是再push一个进去,但是手写堆就不需要这样,只要找到这个元素在堆中位置再尝试向上交换就行了,代码中就是update函数。别的pop(),top()之类操作和普通堆都差不多。最开始要把所有元素放进堆里。

由于每次还要找到一个元素在堆中的位置,所以用index[]数组记录,交换堆中的元素时切记也要交换index[]数组!!!由于index好像重名所以代码中用了define。

#include<bits/stdc++.h>
#define lson (x<<1)
#define rson (x<<1|1)
#define ll long long
#define index ind
using namespace std;
const int N=1000001;
const int M=N*10;
const ll INF=1e18;
int n,m;
int T,rxa,rxc,rya,ryc,rp;
int cnt,Next[M],head[N],v[M],w[M];
ll dis[N];
int h[N],index[N];
int L;
bool b[N];

inline void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

inline void read(ll &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

inline void add(ll x,ll y,ll z){
    Next[++cnt]=head[x];
    head[x]=cnt;
    v[cnt]=y;
    w[cnt]=(int) z;
}

void Swap(int x,int y){
    swap(index[h[x]],index[h[y]]);
    swap(h[x],h[y]);
}

void update(int u){
    int x=index[u];
    while(x>1&&dis[h[x]]<dis[h[x>>1]]){
        Swap(x,x>>1);
        x>>=1;
    }
}

int top(){
    return h[1];
}

void pop(){
    h[1]=h[L--];
    index[h[1]]=1;    //就是少写了这一句呜呜呜
    h[L+1]=0;
    int x=1;
    while(rson<=L){
        if (dis[h[x]]<=dis[h[lson]]&&dis[h[x]]<=dis[h[rson]]) break;
        int w=0;
        if (dis[h[lson]]<dis[h[rson]]) w=lson;
         else w=rson;
        Swap(w,x);
        x=w;
    }
    if (lson<=L&&dis[h[lson]]<dis[h[x]]) Swap(lson,x);
}

inline void dijk(){
    for(int i=1;i<=n;++i){
        int x=top();
        pop();
        b[x]=1;
        for(int j=head[x];j!=-1;j=Next[j])
         if (!b[v[j]]&&dis[x]+w[j]<dis[v[j]]){
            dis[v[j]]=dis[x]+w[j];
            update(v[j]);
         }
    }
}

int main(){
    memset(head,-1,sizeof head);
    read(n);read(m);
    read(T);read(rxa);read(rxc);read(rya);read(ryc);read(rp);
    ll x=0,y=0,z=0;
    ll a,b;
    for(int i=1;i<=T;++i){   //这一段是生成数据不用管
        x=(x*rxa+rxc)%rp;
        y=(y*rya+ryc)%rp;
        a=min(x%n+1,y%n+1);
        b=max(y%n+1,y%n+1);
        add(a,b,1e8-100*a);
    }
    for(int i=T+1;i<=m;++i){
        read(x);read(y);read(z);
        add(x,y,z);
    }

    memset(dis,0x3f,sizeof dis);
    dis[1]=0;
    for(int i=1;i<=n;i++){   //将元素放进堆里
        h[++L]=i;
        index[i]=i;
    }

    dijk();
    if (dis[n]>1e17) cout<<"-1"<<endl;else cout<<dis[n]<<endl;
    return 0;
}

一开始看到题目还以为是个大水题。。
mdzz调了我两天因为少写了一句交换序号。。拍了30+万组数据才拍出来。。
不知道517从哪里搞来的题 517好像把这题撤了(可能是由于他自己写T了。。)