树链剖分求LCA
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
输入输出样例
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
1 //2018年2月17日20:50:56 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int N = 1000001; 9 const int M = 1000001; 10 11 struct Edge{ 12 int to, len, nxt; 13 }E[M]; 14 int cnt, fir[N], fa[N], top[N], deep[N], siz[N], son[N], val[N]; 15 16 void addEdge(int x, int y, int z=0){ 17 E[++cnt].to = y; 18 E[cnt].len = z; 19 E[cnt].nxt = fir[x]; 20 fir[x] = cnt; 21 } 22 23 void dfs1(int x){ 24 deep[x] = deep[fa[x]] + 1; siz[x] = 1; 25 for(int i=fir[x]; i; i=E[i].nxt){ 26 int to = E[i].to; 27 if(fa[x] != to){ 28 val[to] = E[i].len; 29 fa[to] = x; 30 dfs1(to); 31 siz[x] += siz[to]; 32 if(siz[son[x]] < siz[to]) son[x] = to; 33 } 34 } 35 } 36 37 void dfs2(int x){ 38 if(x == son[fa[x]]) top[x] = top[fa[x]]; 39 else top[x] = x; 40 for(int i=fir[x]; i; i=E[i].nxt) 41 if(fa[E[i].to] == x) 42 dfs2(E[i].to); 43 } 44 45 int query(int x, int y){ 46 for(; top[x]!=top[y]; deep[top[x]]>deep[top[y]]?x=fa[top[x]]:y=fa[top[y]]); //注意这里有个分号!!! 47 return deep[x]<deep[y]?x:y; 48 } 49 50 int n, m, x, y, v, root; 51 int main(){ 52 scanf("%d%d%d", &n, &m, &root); 53 for(int i=1;i<n;i++){ 54 scanf("%d%d", &x, &y); 55 addEdge(x, y); 56 addEdge(y, x); 57 } 58 dfs1(root); 59 dfs2(root); 60 61 for(int i=1;i<=m;i++){ 62 scanf("%d%d", &x, &y); 63 printf("%d\n", query(x, y)); 64 } 65 66 return 0; 67 }