BZOJ 3040最短路
题目描述
给定一个 NN 个点, MM 条有向边的带权图,请你计算从 SS 出发,到每个点的距离。
数据保证你能从 SS 出发到任意点。
输入输出格式
输入格式:
第一行两个整数 NN 、 MM ,表示点数和边数。 第二行六个整数 TT 、 rxarxa 、 rxcrxc 、 ryarya 、 rycryc 、 rprp 。
前 TT 条边采用如下方式生成:
- 初始化 x=y=z=0x=y=z=0 。
- 重复以下过程 TT 次:
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);
则有一条从 aa 到 bb 的,长度为 1e8-100*a1e8−100∗a 的有向边。
后 M-TM−T 条边采用读入方式: 接下来 M-TM−T 行每行三个整数 x,y,zx,y,z ,表示一条从 xx 到 yy 长度为 zz 的有向边。
输出格式:
一个整数,表示 11 到 NN 的最短路。
输入输出样例
说明
1\leq N\leq 10^61≤N≤106 , 1\leq M\leq 10^71≤M≤107
1\leq x,y\leq N1≤x,y≤N , 0<z,rxa,rxc,rya,ryc,rp<2^{31}0<z,rxa,rxc,rya,ryc,rp<231
请采用高效的堆来优化Dijkstra算法。
Solution:
本题实在是毒瘤,而且内存限制还卡的那么死。
思路还是比较正常的堆优化dijkstra,只不过我们用的是更高效的配对堆(pbds中的配对堆)。
然后坑点就是空间很死,为了防止重复入队,我们记录一下堆中每个元素的迭代器,然后在三角不等式更新后直接判断该节点是否已在堆中,若在就直接modify修改值,否则才入队,这样能保证堆中元素不超过$N$。
代码:
#include<bits/stdc++.h> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/priority_queue.hpp> #define il inline #define ll long long #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) using namespace std; using namespace __gnu_pbds; const int N=1000005,M=10000000; const ll inf=100000000000000000; int n,m,s,to[M+5],w[M+5],h[N],net[M+5],cnt; ll dis[N]; int T,rxa,rxc,rya,ryc,rp; bool vis[N]; struct node{ int u;ll d; node(int a=0,ll b=0){u=a,d=b;} bool operator<(const node &a)const {return d>a.d;} }; typedef __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag> heap; heap q; heap::point_iterator id[N]; il int gi(){ int a=0;char x=getchar(); while((x<'0'||x>'9')&&x!='-')x=getchar(); while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar(); return a; } il void add(int u,int v,int c){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt,w[cnt]=c;} il void spfa(){ For(i,2,n) dis[i]=inf; dis[s]=0,q.push(node(s,0)); while(!q.empty()){ node x=q.top();q.pop(); int u=x.u; if(vis[u])continue; vis[u]=1; for(int i=h[u];i;i=net[i]) if(dis[to[i]]>dis[u]+w[i]){ dis[to[i]]=dis[u]+w[i]; if(id[to[i]]==0)id[to[i]]=q.push(node(to[i],dis[to[i]])); else q.modify(id[to[i]],node(to[i],dis[to[i]])); } } } int main(){ n=gi(),m=gi(),T=gi(),rxa=gi(),rxc=gi(),rya=gi(),ryc=gi(),rp=gi(),s=1; ll x=0,y=0,z=0,a,b; m-=T; For(i,1,T){ 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,100000000-100*a); } For(i,1,m) x=gi(),y=gi(),z=gi(),add(x,y,z); spfa(); cout<<dis[n]; return 0; }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~