链式前向星图存储优化
1.前向星存储
前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,
并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.
比如有起点终点和权值为以下的边:
1 2 1 // 1->2 权值为1
2 3 2
3 4 3
1 3 4
4 1 5
1 5 6
4 5 7
重新排列以后就为:
1 2 1
1 3 4
1 5 6 // 以1为开头的集合
2 3 2 // 以2为开头的集合
3 4 3 // 以3为开头的集合
4 1 5
4 5 7 // 以4为开头的集合
由于排序需要nlogn时间,有些慢,可以优化为不需要排序的链式前向星
2.链式前向星
不排序我们就要对顺序做一个记录 :
开辟一个last数组来保存以 i 开头集合最后一个元素的下标idx
举个例子 :
1 2 1 // 1->2 权值为1 ,下标为1
2 3 2 // 下标为2
3 4 3 // 下标为3
1 3 4 // 4
4 1 5 // 5
1 5 6 // 6
4 5 7 // 7
上叙边中,以 1 开头集合最后一个边的下标为 6 (1 5 6 ) ,last[1] = 6;
为了便于后续遍历,last数组初始值赋值为-1
对于边结构体的构造:保存边的权值w,边终点end以及加入集合后前一个边下标pr,pr变量表示该元素的上一个元素的下标idx
举个例子,还是上叙边,边(1 3 4) 的 pr 就为 1 (1 2 1)
而由于last数组的存在,pr的值其实就是现在last[f]中的值(加入一个新元素此时该新元素就是集合最后一个,last[f]就为对应下标)
准备变量
ll last[N]={-1}; //last数组
ll cnt=1; //计数(下标)
struct ed{
ll w;
ll pr;
ll end;
}e[500005]; //边结构体
边的构造输入
void add_e(ll f,ll e,ll w) // 该边的起点f,终点e,权值w
{
e[cnt].w=w;
e[cnt].end=e;
e[cnt].pr=last[f]; // 加入一个新元素此时该新元素就是集合最后一个,last[f]就为对应下标
last[f]=cnt++; // 更新最后一个元素的下标,同时更新cnt
}
构造过程
for(ri i=1;i<=m;++i) // m条边
{
cin >> f >> e >> w;
add_e(f,e,w);
}
最后就是边的遍历
for(ri i=1;i<=n;++i) //n个点
{
//从i集合中最后一位往前遍历,当然第一个元素的pr就为last[]中的初始值-1,为判断终止条件
for(ri j=last[i];j!=-1;j=e[j].pr)
{
cout << i << ' ' << e[j].end << ' ' << e[j].w << endl;
}
}
输出可以自己试试,这里就不贴啦,明白思路就好。