lca,就是求樹上任意兩點的最近公共祖先
(本題與**均為luogu3379)
方法我好像講過乙個,這次把主要的三個一起講一講
<1> 倍增(o(n log n))
我們先考慮最基本的lca,記錄每乙個點的父節點和深度。
對於兩個點x,y,先將它們調到同一高度(令dep[x]>dep[y],即把x向上移(dep[x]-dep[y])步即可,然後一起往上走就可以了。
這複雜度是o(nq)的,所以在此基礎上優化。
用father[i][j]表示點j向上走2^i步時的點是多少(沒有就是-1),然後每次上移只要走log n次即可。
預處理的話 father[i][j]]=father[i-1][father[i-1][j]];遞推即可。
code
#include#include#include
using
namespace
std;
const
int n=500005,p=25
;struct
data
e[n*2+10
];int head[n*2+10
],dep[n],father[p][n],i,j,n,m,x,y,root,k;
inline
void read(int &x)
inline
void write(int
x)inline
void add(int x,int
y)inline
void dfs(int k,int fa,int
d)inline
int lca(int x,int
y)
return father[0
][x];
}int
main()
dfs(root,-1,0
);
for (j=0;j1;++j)
for (i=1;i<=n;++i)
if (father[j][i]==-1) father[j+1][i]=-1; else father[j+1][i]=father[j][father[j][i]];
while (m--)
return0;
}
<2> dfs序+rmq(o(n log n))
不難發現,兩個點的lca就是它們第一次出現的位置之間深度最小的點(證明略)。
所以我們用rmq實現o(1)查詢,預處理是o(n log n)
注意rmq返回的是具體的點而不是深度
不得不提的是資料的first[x],first[y]值不一定是從小到大排的,需要判斷一下(re了很久)
code
#include#include#include
#include
using
namespace
std;
const
int n=500005,p=25
;struct
data
e[n*2+10
];struct
rmqf[p][n*2+10
];int
head[n],first[n],n,m,root,i,j,k,tot,x,y;
inline
void read(int &x)
inline
void write(int
x)inline
void add(int x,int
y)inline
void dfs(int k,int fa,int
d)int
main()
dfs(root,-1,0
);
for (j=1;jj)
for (i=1;i+(1
<1
<=tot;++i)
if (f[j-1][i].x1][i+(1
<<(j-1))].x) f[j][i].x=f[j-1][i].x,f[j][i].num=f[j-1][i].num; else f[j][i].x=f[j-1][i+(1
<<(j-1))].x,f[j][i].num=f[j-1][i+(1
<<(j-1
))].num;
while (m--)
return0;
}
<3> tarjan(o(n+q))
這個我第一次寫這道題的時候已經寫過了,具體看
這裡給一下鄰接表的**(好不容易會打)
code
#include#includeusing
namespace
std;
const
int n=500005
;struct
data
e[n*2+10
];struct
ques
q[n*2+10
];int
head[n],qhead[n],father[n],ans[n],i,k,qk,x,y,n,m,root;
bool
vis[n];
inline
void read(int &x)
inline
void write(int
x)inline
void add(int x,int
y)inline
void qadd(int x,int y,int
z)inline
int getfather(int
k)inline
void dfs(int
k)int
main()
for (i=1;i<=m;++i)
for (i=1;i<=n;++i)
father[i]=i;
dfs(root);
for (i=1;i<=m;++i)
write(ans[i]),putchar('\n
');return0;
}
一些重要的演算法
原文 http coolshell.cn p 2583 下面是一些比較重要的演算法,原文 羅 列了32個,但我覺得有很多是數論裡的或是比較生僻的,和計算機的不相干,所以沒有選取。下面的這些,有的我們經常在用,有的基本不用。有的很常見,有的 很偏。不過了解一下也是好事。也歡迎你留下你覺得有意義的演算法...
一些重要的演算法
酷殼 http coolshell.cn 原文 http coolshell.cn p 2583 下面是一些比較重要的演算法,原文羅列了32個,但我覺得有很多是數論裡的或是比較生僻的,和計算機的不相干,所以沒有選取。下面的這些,有的我們經常在用,有的基本不用。有的很常見,有的很偏。不過了解一下也是好...
一些重要的演算法
下面是一些比較重要的演算法,原文羅列了32個,但我覺得有很多是數論裡的,和計算機的不相干,所以沒有選取。下面的這些,有的我們經常在用,有的基本不用。有的很常見,有的很偏。不過了解一下也是好事。也歡迎你留下你覺得有意義的演算法。注 本篇文章並非翻譯,其中的演算法描述大部份摘自wikipedia,因為維...