【学弟向】图的存储与遍历,最短路,连通性 tarjan,树状数组
学弟向,大佬们别喷。
树状数组
单点修改,前缀查询。
int lbd(int x) {return (x&(-x));}
void gai(int x,int c) {for(int i=x;i<=n;i+=lbd(i)) a[i]+=c;}
int cha(int x) {int da=0;for(int i=x;i;i-=lbd(i)) da+=a[i];return da;}
上面这个模板同样是单点加/单点改/单点取max + 查前缀 max/查前缀和。
查询信息可减就可以直接查区间(两个前缀和减一下)。
优点是代码比线段树短。
什么?你想要更炫酷的序列操作?
哎不是你是不是为难学哥,不久有个讲线段树的学哥你去问他。
图的存储与遍历
链式前向星
const int QAQ=1001,ovo=QAQ*QAQ;
int cnt,head[QAQ],to[ovo],nex[ovo],bq[ovo];
void lian(int u,int v,int w)
{
++cnt;
to[cnt]=v;
nex[cnt]=head[u];
bq[cnt]=w;
head[u]=cnt;
}
void dfs(int x,int dis)
{
for(int i=head[x];i;i=nex[i])
{
int v=to[i],w=bq[i];
dfs(v,dis+w);
}
}
臭链表,我上了高一才明白这个存图,大家不理解可以用 vector。
如果你以后做到需要这种存图的题,那么那时候你再来学这个就很容易了,因为你做到需要找反向边的题说明那时候你已经有一些代码能力。
不过目前可以先不用理解这个。
vector
const int QAQ=1001;
vector<int> dian[QAQ],bian[QAQ];
void lian(int u,int v,int w)
{
dian[u].push_back(v);
bian[u].push_back(w);
}
void dfs(int x,int dis)
{
for(int i=0;i<dian[x].size();i++)
{
int v=dian[x][i],w=bian[x][i];
dfs(v,dis+w);
}
}
最好理解的存图。
最短路
听说大家学过了。
单源最短路 dij、spfa。
多源最短路学弗洛伊德。
这仨够用了,其他的我也没写过。
感觉上
dij 像贪心。
spfa 像乱搞。
弗洛伊德 像 DP。
多源不考虑复杂度时选弗洛伊德。
没负边权选 dij,否则选 spfa。
是不是要给学弟们讲个题???
第一题
第二题
spfa 判负环
连通性 tarjan
这里的连通性并非并查集之类的,把那些东西收起来!
强连通:有向图中任意两个点连通(互相走到)。
强连通分量:极大的强连通子图。(理解一下极大:能括就括,强连通分量的子图不是强连通分量)
感觉更好理解的说法是:强连通子图。
找强连通分量
(注意别忘了我们在有向图)
因为强连通分量任意两个点能互相走到,所以我们直接从一个点开始 dfs,可以构成一个 dfs 树。

浙公网安备 33010602011771号