Duan2baka的各種LCA模板!

2021-08-09 11:23:21 字數 3936 閱讀 3188

(這篇文章是模板向…了解具體思想還是看網上其他詳細講解吧qaq)

lca,即最近公共祖先,是在有根樹中兩個點最近的公共祖先,在樹上問題中非常有用qaq

常用lca求法:

樹鏈剖分lca,顧名思義,就是用樹鏈剖分求lca,兩個節點從各自的重鏈往上跳,跳到一條重鏈上lca就為上面的那個點

複雜度o(n

−qlo

g(n)

) 模板**:(*題為codevs 2370)

#include

#include

#include

#define n 80050

using

namespace

std;

inline

int read() while(!isdigit(c));

do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));

return x*f;

}int n,m,x,y,k,top;

int fir[n],top[n],son[n],size[n],dep[n],dis[n],fa[n];

struct edge

}nex[n<<1];

inline

void add(int x,int y,int k)

void dfs1(int x,int dep,int fa,int dis)

}inline

int query(int x,int y)

int main()

dfs1(1,1,0,0);dfs2(1,1);

m=read();

for(int i=1;i<=m;i++)

return

0;}

考慮乙個比較暴力的做法,即先讓深的點慢慢爬到和另乙個點高度相同,然後一起往上爬值到爬到一起,顯然這樣太暴力了,倍增lca就是對其的一種優化

在每次爬的過程中,這次爬2k

,下次爬2k

−1,直到爬到一起,顯然這種優化效果是非常可觀的

複雜度o(n

−q∗l

og(n

))

模板**如下:

#include

#include

#include

#define n 80050

using

namespace

std;

inline

int read() while(!isdigit(c));

do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));

return x*f;

}int n,m,x,y,k,top;

int fir[n],f[25][n],s[25][n],dep[n];

struct edge

}nex[n<<1];

inline

void add(int x,int y,int k)

void dfs(int x,int fa,int dis,int dep)

}inline

int query(int x,int y)

if(x==y) return sum;//跳到一起就不跳了

for(int i=18;i>=0;i--)

if(f[i][x]!=f[i][y])

return sum+s[0][x]+s[0][y];

}int main()

dfs(1,0,0,1);

for(int j=1;j<=17;j++)

for(int i=1;i<=n;i++)

m=read();

for(int i=1;i<=m;i++)

return

0;}

st表是基於dp上的一種rmp演算法..大概就是要求x和y的lca為尤拉序中x與y中深度最小的那個點,具體證明還是看網上神犇們的題解吧orz…

複雜度o(n

∗log

(n)−

q)

模板**如下:

#include

#include

#include

#include

#define n 800050

using

namespace

std;

inline

int read() while(!isdigit(c));

do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));

return x*f;

}int n,m,x,y,k,top;

int fir[n],s[n<<1],dep[n],fa[n],loc[n],dis[n];

int f[25][n];

struct edge

}nex[n<<1];

inline

void add(int x,int y,int k)

void dfs(int x,int dep,int fa,int dis)

}inline

void init()

}inline

int rmq(int l,int r)

inline

int query(int x,int y)

int main()

top=0;

dfs(1,1,0,0);

init();

m=read();

for(int i=1;i<=m;i++)

return

0;}

又是tarjan…

tarjan求lca是這幾個演算法中唯一乙個離線演算法,複雜度極優

演算法思想大致是隨便從乙個點走遍歷所有子樹後把所有子樹的fa都改為這個點,如果遍歷完x時y已經走過了,則他倆的lca就是y的祖先(find(y))

複雜度o(n

+q) ,順便問候tarjan及他工作室的小夥伴

模板**如下:

#include

#include

#define n 80050

using

namespace

std;

inline

int read() while(!isdigit(c));

do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));

return x*f;

}int n,m,x,y,k,top,top;

int fa[n],dis[n],fir[n],fir[n],f[n],ans[n],fx[n],fy[n];

bool b[n];

struct edge

}nex[n*2],nex[n*2];

void dfs(int x,int dis,int fa)

}inline

void add(int x,int y,int k,int &top,int fir,edge nex)

int find(int x)

inline

void link(int x,int y)

void tarjan(int x)

for(int i=fir[x];i;i=nex[i].nex)

if(b[nex[i].to])

ans[nex[i].k]=find(nex[i].to);

}int main()

f[n]=n;

dfs(1,0,0);

m=read();

for(int i=1;i<=m;i++)

tarjan(1);

for(int i=1;i<=m;i++)

return

0;}

各種求lca的辦法

1.暴力求 2.倍增求 3.用rmq求 4.用tarjan離線求 5.用樹鏈剖分求 6.剛看到有乙個轉成二進位制求的 有點懵逼 1.關於暴力 有的時候是很快的 深度比較小 有時可以人為構造 如按秩合併 大部分時間可以被卡過,所以不是個好方法,但暴力出奇蹟啊,簡單地說就是乙個乙個往上找。我有個比較優美...

LCA的簡單變形(2)尋找中點

題目描述 windy 和 zero 居住在同乙個國家,該國家有n個城市。windy 居住在 x 城市,zero 居住在 y 城市。任意兩個城市之間有且只有一條路徑相通 中間可能經過其它城市 有一天,windy 和 zero 想見面,他們想把見面的地點定在城市 x 和城市 y 的中間。現在請你告訴他們...

Struts2的iterator各種用法

4 普通屬性 public string execute username password 5 自定義物件 public string execute userinfo.username userinfo.password 6 list 普通屬性 public string execute lis...