(這篇文章是模板向…了解具體思想還是看網上其他詳細講解吧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...