https://www.cnblogs.com/JVxie/p/4854719.html
不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻
这是个离线算法,现在的粗略理解是输入完毕询问完毕后进行解决的算法
用了并查集
1···选取根节点
2···逐个dfs访问所选节点所有的子节点v
3···1··对于子节点的dfs访问到头之后
3···2··标记,进行询问查询
3···3··如果查询的点访问过,输出其目前祖先
4···回溯,合并边,更新pre数组(并查集)
5.所有节点访问完毕,结束
1.任选一个点为根节点,从根节点开始。
2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。
3.若是v还有子节点,返回2,否则下一步。
4.合并v到u上。
5.寻找与当前点u有询问关系的点v。
6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点
模拟别人打了一下代码
#include <iostream> #include <cstdio> #include <string.h> using namespace std; const int maxn = 1000; const int maxm = 1000; struct node{ int to,pre; }e[maxn * maxn],q[maxn * maxn]; int pre[maxn]; bool vis[maxn]; int id[maxn],cnt; int idq[maxn],cntq; int in[maxn]; int ans[maxn]; int root; void init(int n) { memset(id,-1,sizeof(id)); memset(idq,-1,sizeof(idq)); cntq = 0; cnt = 0; memset(in,0,sizeof(in)); memset(ans,0,sizeof(ans)); memset(vis,0,sizeof(vis)); for(int i = 0;i <= n;i++) pre[i] = i; } void add(int from,int to) { e[cnt].to = to; e[cnt].pre = id[from]; id[from] = cnt++; } void addq(int from,int to) { q[cntq].to = to; q[cntq].pre = idq[from]; idq[from] = cntq++; } int Find(int x) { if(pre[x] == x)return x; return pre[x] = Find(pre[x]); } void join(int u,int v) { int fu = Find(u); int fv = Find(v); pre[fv] = fu; } void LCA(int rt) { for(int i = id[rt];~i;i = e[i].pre) { int to = e[i].to; LCA(to); join(rt,to); } vis[rt] = 1; for(int i = idq[rt];~i;i = q[i].pre) { int que = q[i].to; if(vis[que]) ans[Find(que)]++; } } int main() { int n; while(~scanf("%d",&n)) { init(n); int x,y,z; for(int i = 0;i < n;i++) { scanf("%d:(%d)",&x,&y); for(int j = 0;j < y;j++) { scanf("%d",&z); in[z] = 1; add(x,z); } } int t; scanf("%d",&t); while(t--) { while(getchar() !='('); scanf("%d%d",&x,&y); addq(x,y); addq(y,x); } while(getchar() != ')'); for(int i = 1;i <= n;i++) if(!in[i])root = i; LCA(root); for(int i = 1;i <= n;i++) { if(ans[i] != 0) printf("%d:%d ",i,ans[i]); } } return 0; }
现在我要自己去大一下模板提啦
http://node2.vjmirror.rainng.com/contest/241642#problem/A
题意也是模板题意,很简单,错了两个地方都是小失误。。。。
一个是两个for循环索引都是i
另一个是空间没开够
略略略
#include <iostream> #include <cstdio> #include <string.h> using namespace std; const int maxn = 1100; int id[maxn],cnt; int qid[maxn],qcnt; struct node { int to,pre; }e[maxn]; struct node2 { int to,ID,pre; }q[maxn * 3]; int pre[maxn]; bool vis[maxn]; int ans[maxn]; void init(int n) { memset(id,-1,sizeof(id)); memset(qid,-1,sizeof(qid)); memset(vis,0,sizeof(vis)); cnt = qcnt = 0; for(int i = 0;i <= n;i++) pre[i] = i; } void add(int from,int to) { e[cnt].to = to; e[cnt].pre = id[from]; id[from] = cnt++; } void qadd(int from,int to,int I) { q[qcnt].to = to; q[qcnt].pre = qid[from]; q[qcnt].ID = I; qid[from] = qcnt++; } int Find(int x) { if(x == pre[x])return x; return pre[x] = Find(pre[x]); } void join(int u,int v) { int fu = Find(u),fv = Find(v); if(fu != fv) pre[fv] = fu; } void tarjan(int rt) { //cout<<"cs"<<" "<<rt<<endl; for(int i = id[rt];~i;i = e[i].pre) { int to = e[i].to; tarjan(to); join(rt,to); } vis[rt] = 1; for(int i = qid[rt];~i;i = q[i].pre) { int que = q[i].to; if(vis[que]) { ans[q[i].ID] = Find(que); //cout<<Find(que)<<endl; } } } int main() { int t,n,m; scanf("%d",&t); int cas = 1; while(t--) { scanf("%d",&n); init(n); for(int i = 1;i <= n;i++) { int n_num,v; scanf("%d",&n_num); for(int j = 0;j < n_num;++j) { scanf("%d",&v); add(i,v); } } scanf("%d",&m); int u,v; for(int i = 1;i <= m;i++) { scanf("%d%d",&u,&v); qadd(u,v,i); qadd(v,u,i); } tarjan(1); printf("Case %d: ",cas++); for(int i = 1;i <= m;i++) { printf("%d ",ans[i]); } } return 0; }