对于最近公共祖先问题,我们先来看这样一个性质,当两个节点(u,v)的最近公共祖先是x时,那么我们可以确定的说,当进行后序遍历的时候,必然先访问完x的所有子树,然后才会返回到x所在的节点。这个性质就是我们使用Tarjan算法解决最近公共祖先问题的核心思想。
同时我们会想这个怎么能够保证是最近的公共祖先呢?我们这样看,因为我们是逐渐向上回溯的,所以我们每次访问完某个节点x的一棵子树,我们就将该子树所有节点放进该节点x所在的集合,并且我们设置这个集合所有元素的祖先是该节点x。那么我们有理由相信, 任何一个不属于已经访问的节点和已经访问的节点的LCA一定是当前这个根节点. 于是我们每次访问完一棵子树, 只需要将子树放进根节点对应的集合即可.
poj 1470 :给出一棵树,给出若干个u,v,然后求出u,v的lca,输出每个点座位lca的次数,
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn = 100000 + 10; typedef long long ll; #define clr(x,y) memset(x,y,sizeof x) #define INF 0x3f3f3f3f const ll Mod = 1e9 + 7; typedef pair<int,int> P; vector<int>g[maxn],q[maxn]; int ans[maxn],fa[maxn],in[maxn]; bool vis[maxn]; int finds(int x) { return fa[x] == x ? x : (fa[x] = finds(fa[x])); } void dfs(int u) { fa[u] = u; for(int i = 0;i < g[u].size();i ++) { int v = g[u][i]; dfs(v);fa[v] = u; } vis[u] = true; for(int i = 0;i < q[u].size();i ++) { int v = q[u][i]; if(vis[v]) { int lca = finds(v);ans[lca] ++; } } } int main() { int n;char s[3]; while( ~ scanf("%d",&n)) { int root;clr(ans,0);clr(vis,false);clr(in,0); for(int i = 1;i <= n;i ++)g[i].clear(),q[i].clear(); for(int i = 1;i <= n;i ++) { int x,y;scanf("%d:(%d)",&x,&y); for(int j = 1;j <= y;j ++) { int z;scanf("%d",&z); g[x].push_back(z); in[z] ++; } } int m;scanf("%d",&m); while(m --) { int x,y;scanf(" (%d%d)",&x,&y); q[x].push_back(y);q[y].push_back(x); } for(int i = 1;i <= n;i ++)if(!in[i]){root = i;break;} dfs(root); for(int i = 1;i <= n;i ++) if(ans[i])printf("%d:%d\n",i,ans[i]); } return 0; }
hdu 4547
题意:两种CD操作,一种是可以直接访问当前目录下的任何一个子目录或者文件,一种是返回上一级。操作次数都为1.
思路:求出lca,进行操作。应为都为查询,所以可以离线。
#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 1e5 + 10; typedef long long ll; #define clr(x,y) memset(x,y,sizeof x) #define INF 0x3f3f3f3f const ll Mod = 1e9 + 7; typedef pair<int,int> P; map<string,int>ms; vector<int>g[maxn]; struct Node { int dir; int pos; int to; }; int ans[maxn],lca[maxn]; vector<Node>q[maxn]; int in[maxn],fa[maxn],dep[maxn]; bool vis[maxn]; int finds(int x) { return fa[x] == x ? x : (fa[x] = finds(fa[x])); } void dfs(int u,int d) { fa[u] = u;dep[u] = d; for(int i = 0;i < g[u].size();i ++) { int v = g[u][i]; dfs(v,d + 1); fa[v] = u; } vis[u] = true; for(int i = 0;i < q[u].size();i ++) { Node t = q[u][i]; if(vis[t.to]) { lca[t.pos] = finds(t.to); } } } int U[maxn],V[maxn]; int main() { ios::sync_with_stdio(false); int Tcase;cin >> Tcase; while(Tcase --) { int n,m;cin >> n >> m; for(int i = 1;i <= n;i ++)g[i].clear(),q[i].clear(); ms.clear();int tot = 0; clr(in,0);clr(vis,false);clr(lca,0); for(int i = 1;i <= n - 1;i ++) { string A,B;cin >> A >> B; if(!ms[A])ms[A] = ++ tot; if(!ms[B])ms[B] = ++ tot; g[ms[B]].push_back(ms[A]); in[ms[A]] ++; } for(int i = 1;i <= m;i ++) { string A,B;cin >> A >> B; q[ms[A]].push_back((Node){1,i,ms[B]}); q[ms[B]].push_back((Node){-1,i,ms[A]}); U[i] = ms[A];V[i] = ms[B]; } for(int i = 1;i <= n;i ++) { if(!in[i] && !vis[i]) { dfs(i,1);break; } } for(int i = 1;i <= m;i ++) { ans[i] = 0; ans[i] += dep[U[i]] - dep[lca[i]]; if(V[i] != lca[i])ans[i] ++; } for(int i = 1;i <= m;i ++) cout << ans[i] << endl; } return 0; }