标签:
题意:给出一棵树,1为根节点,求一段区间内所有点的最近公共祖先。
解法:用一棵线段树维护区间LCA。LCA是dp做法。dp[i][j]表示点i的第2^j个祖先是谁,转移方程为dp[i][j] = dp[dp[i][j - 1]][j - 1],初始的dp[i][0]可以用一次dfs求得,这样可以用logn的时间求第x个祖先或查询LCA。求第x个祖先可以从二进制的角度理解,假设x是10,转化为二进制是1010,那么只要升2^3 + 2^1个深度就可以求出第x个祖先。求LCA的具体做法是,先将点a和b升至同一深度,如果此时a和b为同一个点,说明LCA就是a(或者b),如果不是同一个点,再同时向上升,直到已经无法找到两个点的祖先是不同点,说明两个点已经升至LCA的下一层,再向上升一层即为LCA。
然后就是建一棵线段树,只需要查询,没有更新,查询的写法纠结了好久……
因为代码写的太屎了,扩栈了依然会RE……所以只好用栈模拟……但是不扩栈又会T……不太理解那句扩栈用的语句的原理TUT……5000+ms擦边过了……
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #pragma comment(linker, "/STACK:10240000000, 10240000000") using namespace std; vector <int> tree[300005]; bool vis[300005]; int deep[300005]; int dp[300005][30]; int st[300005 << 2]; struct node { int rt, dep; node(int rt, int dep) : rt(rt), dep(dep) {} node() {} }; stack <node> s; int LCA(int a, int b) { if(deep[a] < deep[b]) swap(a, b); for(int i = 20; i >= 0; i--) { if(deep[a] == deep[b]) break; if(deep[dp[a][i]] >= deep[b]) a = dp[a][i]; } if(a == b) return a; for(int i = 20; i >= 0; i--) { if(dp[a][i] != dp[b][i]) { a = dp[a][i]; b = dp[b][i]; } } return dp[a][0]; } void pushUp(int rt) { st[rt] = LCA(st[rt << 1], st[rt << 1 | 1]); } void build(int l, int r, int rt) { if(l == r) { st[rt] = l; return ; } int m = (l + r) >> 1; build(lson); build(rson); pushUp(rt); } int query(int ll, int rr, int l, int r, int rt) { if(ll <= l && rr >= r) return st[rt]; int m = (l + r) >> 1; int res; if(ll <= m) { res = query(ll, rr, lson); if(rr > m) return LCA(res, query(ll, rr, rson)); else return res; } else return query(ll, rr, rson); } int main() { int n; while(~scanf("%d", &n)) { for(int i = 0; i < 300005; i++) tree[i].clear(); for(int i = 0; i < n - 1; i++) { int a, b; scanf("%d%d", &a, &b); tree[a].push_back(b); tree[b].push_back(a); } memset(vis, 0, sizeof vis); memset(dp, 0, sizeof dp); vis[1] = true; dp[1][0] = 1; s.push(node(1, 1)); while(!s.empty()) { node top = s.top(); deep[top.rt] = top.dep; int len = tree[top.rt].size(); int flag = true; for(int i = 0; i < len; i++) { if(!vis[tree[top.rt][i]]) { vis[tree[top.rt][i]] = true; dp[tree[top.rt][i]][0] = top.rt; s.push(node(tree[top.rt][i], top.dep + 1)); flag = false; } } if(flag) s.pop(); } for(int j = 1; j < 20; j++) { for(int i = 1; i <= n; i++) { dp[i][j] = dp[dp[i][j - 1]][j - 1]; } } build(1, n, 1); int q; scanf("%d", &q); for(int i = 0; i < q; i++) { int a, b; scanf("%d%d", &a, &b); printf("%d\n", query(a, b, 1, n, 1)); } } return 0; }
标签:
原文地址:http://www.cnblogs.com/Apro/p/4563247.html