题目大意:给定n个点m条边的图,求1~n的最短路 n<=100W m<=1000W
题目上说要用高效的堆来优化Dijkstra 于是我们自然而然就会想到斐波那契堆 但是那东西真的不是很好写 于是我们有很高效的替代品——Pairing-Heap(配对堆)
这东西真的很好写(除了手写栈以外,一个节点有多个儿子所以手写了栈)
首先Pairing-Heap有几个基本操作:
Merge(x,y) 将两堆合并 直接将权值比较大的点挂在较小的下面当做儿子即可
Insert(x) 插入一个点 直接将x与根节点合并
Decrease_Key(x) 将x的权值减小 如果x是根节点则无视 否则直接将x与父节点断开 然后将x与根节点合并
Pop() 删除根节点 将根节点的所有儿子都拎出来 从左到右两两合并 然后从右到左两两合并 反复如此直到只剩下一个儿子为止 然后将这个儿子作为新的根节点
其中除了Pop以外所有的操作都是O(1)的 而Pop操作可以证明是均摊O(logn) (我不会证)
对于Dijkstra算法来说,我们需要执行最多m次Decrease_Key 于是Decrease_Key操作优化到O(1)是十分有利的 也就是把Dijkstra的复杂度优化到了O(nlogn+m)
实现的时候由于网上很难找到相关代码 所以我第一次写的时候写挂了0.0…… 今天也是一顿神WA 才搞定0.0
对于每个节点 记录父亲节点 开一个栈记录所有的子节点 然后再开一个域记录键值
注意这里的栈不能用STL中的stack 因为stack在申请空间的时候默认申请五个变量 加上指针一共十倍 这十倍的空间足够让你MLE了
可以用vector代替栈或者干脆手写 我选择了手写QAQ
对于Merge(x,y)操作 设x为权值较小的节点 y为较大的 将y的父亲设为x 然后将x的儿子中插入y
对于Decrease_Key(x)操作 首先将x的父亲设为空 注意无需将x的父亲的儿子中删除x 然后将x与root合并
对于Pop()操作 首先开两个指针指向两个栈 然后对于根节点的每一个儿子 如果这个儿子的父亲是root 那么将这个儿子的父亲设为空 然后加入栈1
然后将栈1的节点两两配对 配对后的节点加入栈2 反复如此直到栈1中的元素不足两个 然后将栈1中的剩余元素(如果有)扔进栈2 交换两栈的指针
反复如此直到栈1中的元素只剩一个 此时将这个元素设为新的根节点 Pop()操作完成
于是Pairing-Heap的操作就完成了 加上Dijkstra的模板即可 不明白的地方详见代码
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1000010
using namespace std;
typedef long long ll;
struct abcd{
int to,f,next;
}table[M*6];
int head[M],tot;
int n,m;
ll X,Y,T,rxa,rxc,rya,ryc,rp;
namespace IStream{
const int L=1<<15;
char buffer[L];
char *S,*T;
inline char Get_Char()
{
if(S==T)
{
T=(S=buffer)+fread(buffer,1,L,stdin);
if(S==T) return EOF;
}
return *S++;
}
inline int Get_Int()
{
int re=0;
char c;
do c=Get_Char(); while(c<'0'||c>'9');
while(c>='0'&&c<='9')
re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
return re;
}
}
namespace Pairing_Heap{
struct Heap;
struct Stack_Point{
Heap *mem;
Stack_Point *last;
void* operator new (size_t,Heap *_,Stack_Point *__);
void operator delete (void *p);
};
stack<void*>bin;
void* Stack_Point :: operator new (size_t,Heap *_,Stack_Point *__)
{
if( bin.size() )
{
Stack_Point *re=(Stack_Point*)bin.top();bin.pop();
re->mem=_;re->last=__;
return re;
}
static Stack_Point *mempool,*C;
if(C==mempool)
{
C=new Stack_Point[1<<15];
mempool=C+(1<<15);
}
C->mem=_;
C->last=__;
return C++;
}
void Stack_Point :: operator delete (void *p)
{
bin.push(p);
}
class Stack{
private:
Stack_Point *top;
int size;
public:
inline Heap* Top()
{
return top->mem;
}
inline void Pop()
{
delete top;
top=top->last;
--size;
}
inline bool Empty()
{
return size==0;
}
inline int Size()
{
return size;
}
inline void Push(Heap* x)
{
top=new (x,top) Stack_Point;
++size;
}
};
struct Heap{
Heap *fa;
Stack son;
ll f;
}*root,heap[M];
inline Heap* Merge(Heap *x,Heap *y)
{
if( x->f > y->f )
swap(x,y);
y->fa=x;
x->son.Push(y);
return x;
}
inline void Decrease_Key(Heap *x)
{
if(x==root)
return ;
x->fa=0x0;
root=Merge(x,root);
}
inline void Pop()
{
static Stack stack1,stack2;
Stack *s1=&stack1,*s2=&stack2;
while( !root->son.Empty() )
{
if(root->son.Top()->fa==root)
{
s1->Push( root->son.Top() ),
root->son.Top()->fa=0x0;
}
root->son.Pop();
}
while(s1->Size()>=2)
{
while(s1->Size()>=2)
{
Heap *temp1=s1->Top();s1->Pop();
Heap *temp2=s1->Top();s1->Pop();
s2->Push( Merge(temp1,temp2) );
}
if( s1->Size() )
s2->Push( s1->Top() ),s1->Pop();
swap(s1,s2);
}
if( s1->Size() )
root=s1->Top(),s1->Pop();
}
void Initialize()
{
int i;
root=&heap[1];
for(i=2;i<=n;i++)
{
heap[i].f=4557430888798830399ll;
heap[i].fa=root;
heap[1].son.Push(&heap[i]);
}
}
}
void Add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
ll Dijkstra()
{
int i,j;
Pairing_Heap::Initialize();
for(j=1;j<=n;j++)
{
int x=(Pairing_Heap::root)-(Pairing_Heap::heap);
Pairing_Heap::Pop();
if(x==n) return Pairing_Heap::heap[n].f;
for(i=head[x];i;i=table[i].next)
if(Pairing_Heap::heap[table[i].to].f>Pairing_Heap::heap[x].f+table[i].f)
{
Pairing_Heap::heap[table[i].to].f=Pairing_Heap::heap[x].f+table[i].f;
Pairing_Heap::Decrease_Key(&Pairing_Heap::heap[table[i].to]);
}
}
}
int main()
{
//freopen("3040.in","r",stdin);
//freopen("3040.out","w",stdout);
int i,x,y,z;
cin>>n>>m;
cin>>T>>rxa>>rxc>>rya>>ryc>>rp;
for(i=1;i<=T;i++)
{
X=(X*rxa+rxc)%rp;
Y=(Y*rya+ryc)%rp;
x=min(X%n+1,Y%n+1);
y=Y%n+1;
z=100000000-100*x;
if(x!=y) Add(x,y,z);
}
for(i=T+1;i<=m;i++)
{
x=IStream::Get_Int();
y=IStream::Get_Int();
z=IStream::Get_Int();
Add(x,y,z);
}
cout<<Dijkstra()<<endl;
}