Poj--1470(LCA,离线tarjan / 在线倍增)

2014-10-26 12:13:10

思路:lca启蒙题,比较裸的一题,水过吧。有离线Tarjan和在线倍增两种做法。

离线Tarjan:

 

  1 /*************************************************************************
  2     > File Name: 1470.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com 
  5     > Created Time: Sat 25 Oct 2014 06:50:04 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <stack>
 16 #include <queue>
 17 #include <iostream>
 18 #include <algorithm>
 19 using namespace std;
 20 #define lp (p << 1)
 21 #define rp (p << 1|1)
 22 #define getmid(l,r) (l + (r - l) / 2)
 23 #define MP(a,b) make_pair(a,b)
 24 typedef long long ll;
 25 const int INF = 1 << 30;
 26 const int maxn = 1000;
 27 
 28 int n,m;
 29 int first[maxn],next[maxn * maxn],ver[maxn * maxn],ecnt;
 30 int fa[maxn];
 31 int que[maxn][maxn];
 32 int vis[maxn];
 33 int cnt[maxn],f[maxn];
 34 
 35 int Find(int x){
 36     return fa[x] == x ? x : fa[x] = Find(fa[x]); //并查集find,路径压缩
 37 }
 38 
 39 void Union(int u,int v){
 40     int x = Find(u);
 41     int y = Find(v);
 42     if(x != y)
 43         fa[y] = x; //后者以前者为祖先
 44 }
 45 
 46 void Add_edge(int u,int v){
 47     next[++ecnt] = first[u];
 48     ver[ecnt] = v;
 49     first[u] = ecnt;
 50 }
 51 
 52 void Init(){
 53     memset(f,0,sizeof(f));
 54     memset(cnt,0,sizeof(cnt));
 55     memset(que,0,sizeof(que));
 56     memset(vis,0,sizeof(vis));
 57     memset(first,-1,sizeof(first));
 58     ecnt = 0;
 59 }
 60 
 61 void Tarjan(int p){
 62     fa[p] = p; //先把遍历到的点p自己加入一个集合
 63     for(int i = first[p]; i != -1; i = next[i]){
 64         int v = ver[i];
 65         Tarjan(v); //遍历子节点
 66         Union(p,v); //因为p是其所有子节点的祖先,所以并进集合,并以p为祖先
 67     }
 68     vis[p] = 1; //表示以p为根的整棵子树已经访问完毕
 69     for(int i = 1; i <= n; ++i) if(que[p][i] && vis[i]){
 70         cnt[Find(i)] += que[p][i];
 71         //询问的是(p,i),如果i已经访问过,那么说明遍历到lca(p,i)时
 72         //是先遍历到包含i的子树,再遍历包含p的子树。那么i当前的最祖先节点必然
 73         //是p和i的最近公共祖先(因为i的最祖先节点是不断更新的,一旦能发现p点,
 74         //那么当前最祖先节点是最近的。)
 75 
 76         //que[p][i] = que[i][p] = 0;
 77         //上句话其实没有必要,因为一对关系只会求一次。每次关系会处理到
 78         //两次,必定有一次是只有一个点遍历过,另一个点没有遍历过
 79     }
 80 }
 81 
 82 int main(){
 83     int a,b,k;
 84     while(scanf("%d",&n) != EOF){
 85         Init();
 86         for(int i = 1; i <= n; ++i){
 87             scanf("%d:(%d)",&a,&k);
 88             while(k--){
 89                 scanf("%d",&b);
 90                 Add_edge(a,b); //单条有向边
 91                 f[b] = 1; //用于区别出根节点与其他节点
 92             }
 93         }
 94         char c;
 95         scanf("%d",&m);
 96         for(int i = 1; i <= m; ++i){
 97             c = getchar();
 98             while(c != '(') c = getchar();
 99             scanf("%d%d",&a,&b);
100             c = getchar();
101             while(c != ')') c = getchar();
102             que[a][b]++; //对称地记录询问
103             que[b][a]++;
104         }
105         for(int i = 1; i <= n; ++i)
106             if(!f[i]){
107                 Tarjan(i); //i就为整棵树的根节点
108                 break;
109             }
110         for(int i = 1; i <= n; ++i) if(cnt[i]){
111             printf("%d:%d\n",i,cnt[i]);
112         }
113     }
114     return 0;
115 }
View Code

 

在线倍增(后学):

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <queue>
 10 #include <string>
 11 #include <iostream>
 12 #include <algorithm>
 13 using namespace std;
 14 
 15 #define MEM(a,b) memset(a,b,sizeof(a))
 16 #define REP(i,n) for(int i=1;i<=(n);++i)
 17 #define REV(i,n) for(int i=(n);i>=1;--i)
 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i)
 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 21 #define MP(a,b) make_pair(a,b)
 22 
 23 typedef long long ll;
 24 typedef pair<int,int> pii;
 25 const int INF = (1 << 30) - 1;
 26 const int MAXN = 1010;
 27 const int MAX_LOG = 10;
 28 
 29 int n,m,first[MAXN],ecnt,f[MAXN],root;
 30 int fa[11][MAXN],dep[MAXN];
 31 int lca[MAXN];
 32 
 33 struct edge{
 34     int v,next;
 35 }e[MAXN * MAXN];
 36 
 37 void Add_edge(int u,int v){
 38     e[++ecnt].next = first[u];
 39     e[ecnt].v = v;
 40     first[u] = ecnt;
 41 }
 42 
 43 void Dfs(int p,int pre,int d){
 44     fa[0][p] = pre;
 45     dep[p] = d;
 46     for(int i = first[p]; ~i; i = e[i].next){
 47         int v = e[i].v;
 48         if(v == pre) continue;
 49         Dfs(v,p,d + 1);
 50     }
 51 }
 52 
 53 void Init(){
 54     Dfs(root,-1,0);
 55     for(int k = 0; k + 1 < MAX_LOG; ++k){
 56         for(int i = 1; i <= n; ++i){
 57             if(fa[k][i] < 0) fa[k + 1][i] = -1;
 58             else fa[k + 1][i] = fa[k][fa[k][i]];
 59         }
 60     }
 61 }
 62 
 63 void Lca(int u,int v){
 64     if(dep[u] > dep[v]) swap(u,v);
 65     for(int k = 0; k < MAX_LOG; ++k){
 66         if((dep[v] - dep[u]) & (1 << k))
 67             v = fa[k][v];
 68     }
 69     if(u == v){
 70         lca[u]++;
 71         return;
 72     }
 73     for(int k = MAX_LOG - 1; k >= 0; --k){
 74         if(fa[k][u] != fa[k][v]){
 75             u = fa[k][u];
 76             v = fa[k][v];
 77         }
 78     }
 79     lca[fa[0][u]]++;
 80 }
 81 
 82 int main(){
 83     char c;
 84     int a,b,k;
 85     while(scanf("%d",&n) != EOF){
 86         MEM(first,-1);
 87         MEM(f,0);
 88         MEM(lca,0);
 89         ecnt = 0;
 90         REP(i,n){
 91             scanf("%d:(%d)",&a,&k);
 92             while(k--){
 93                 scanf("%d",&b);
 94                 Add_edge(a,b);
 95                 f[b] = 1;
 96             }
 97         }
 98         REP(i,n) if(!f[i]){
 99             root = i;
100             break;
101         }
102         Init();
103         scanf("%d",&m);
104         REP(i,m){
105             c = getchar();
106             while(c != '(') c = getchar();
107             scanf("%d%d",&a,&b);
108             while(c != ')') c = getchar();
109             Lca(a,b);
110         }
111         REP(i,n) if(lca[i])
112             printf("%d:%d\n",i,lca[i]);
113     }
114     return 0;
115 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4051830.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值