1到4的最短距離?
前提:邊的權重不能有負的
找可以確定的最短距離
紀錄有沒有走過
priority_queue
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define ff first
#define ss second
#deifne N 200010
vector<pii> adj[N];
bitset<N> vis;
int dis[N];
void Dijkstra(int v){
priority_queue<pii> pq;
for(auto u:adj[v]) pq.push({-u.ss,u.ff});
vis[v]=1;
while(!pq.empty()){
auto v=pq.top();pq.pop();
if(vis[v.ss]) continue;
vis[v.ss]=1,dis[v.ss]=-v.ff;
for(auto u:adj[v]) pq.push({v.ff-u.ss,u.ff});
}
}
使一個圖連通的最小權重
跟Dijkstra幾乎一樣
觀察一下
只要取不同連通塊的最小的邊就好了
有兩種操作
1.查詢x在哪個集合
2.合併a, b集合
可以讓每個集合可以有一個代表元素
這樣就可以判連通塊了
實作
int root[x];
//若root[x]<0
//則x為該集合的代表元素
int find(int x){
if(root[x]<0) return x;
return find(root[x]);
}
void Union(int a,int b){
a=find(a),b=find(b);
if(a==b) return;
root[b]=a;
}
小的合到大的
int find(int x){
if(root[x]<0) return x;
return root[x]=find(root[x]);
}
if(size[a]<size[b]) swap(a,b);
size[a]+=size[b];
如果加上面兩個優化並查集的複雜度小到可以當常數
只加一個會降成log
LCA
時間戳記
啟發式合併
(u,v)深度最深的共同祖先即(u,v)的lca
#include<bits/stdc++.h>
using namespace std;
#define N 200010
int n,dep[N],fa[20][N];
vector<int>c[N];
void dfs(int v,int f){
for(int u:c[v]) if(u!=f){
dep[u]=dep[v]+1;
fa[0][u]=v;
dfs(u,v);
}
}
void init(){
dfs(1,-1);
for(int i=1;i<20;i++) for(int j=1;j<=n;j++)
fa[i][j]=fa[i-1][fa[i-1][j]];
}
int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int d=dep[u]-dep[v];
for(int i=19;i>=0;i--)
if(d&(1<<i)) u=fa[i][u];
if(u==v) return v;
for(int i=19;i>=0;i--)
if(fa[i][u]!=fa[i][v]) u=fa[i][u],v=fa[i][v];
return fa[0][u];
}
(u,v) 的距離=dep[u]+dep[v]-dep[lca(u,v)]*2
紀錄出入的時間
in:1 2 3 4 5 6
out: 3 2 5 6 4 1
判斷u是否為v的祖先
in[v]<in[u]&&out[v]>out[u]
Text
把回頭編號加上去
1 2 3 3 2 1 4 5 5 4 6 6 4 1
(u,v)經過的路徑
in[u]<in[v]
if out[u]>in[v] 經過的路徑為(in[u],in[v])
else (out[u],in[v])