最近公共祖先

  1 /*
  2   题意:最近公共祖先
  3   题解:tarjan算法实现
  4   时间:2018.07.18
  5 */
  6 
  7 #include <bits/stdc++.h>
  8 using namespace std;
  9 
 10 typedef long long LL;
 11 const int MAXN = 100005;
 12 const LL MOD7 = 1e9+7;
 13 
 14 struct Edge
 15 {
 16     int u,v;
 17     int next;
 18 }edge[4*MAXN];
 19 int head[MAXN];
 20 int cnt;
 21 
 22 struct Query
 23 {
 24     int u,v;
 25     int ans;
 26     int idx;
 27 }Qe[MAXN];
 28 vector<int> g[MAXN];
 29 
 30 int f[MAXN];
 31 int vis[MAXN];
 32 
 33 map<string,int> names;
 34 map<int,string> ids;
 35 int K;
 36 
 37 int n,Q;
 38 
 39 void init()
 40 {
 41     cnt=0;
 42     memset(head,-1,sizeof(head));
 43 }
 44 
 45 void addEdge(int u,int v)
 46 {
 47     edge[cnt].u=u;edge[cnt].v=v;edge[cnt].next=head[u];head[u]=cnt++;
 48 }
 49 
 50 int Find(int x)
 51 {
 52     if (x==f[x]) return x;
 53     return f[x]=Find(f[x]);
 54 }
 55 
 56 void union_set(int x,int y)
 57 {
 58     int fx=Find(x);
 59     int fy=Find(y);
 60     if (fx!=fy)
 61         f[fx]=fy;
 62 }
 63 
 64 void tarjan(int u)
 65 {
 66     vis[u]=1;
 67     for (int i=head[u];i!=-1;i=edge[i].next)
 68     {
 69         int v=edge[i].v;
 70         if (!vis[v])
 71         {
 72             tarjan(v);
 73             union_set(v,u);
 74         }
 75     }
 76     for (int i:g[u])
 77     {
 78         int v = Qe[i].v;
 79         if (v==u) v=Qe[i].u;
 80         if (vis[v]) Qe[i].ans = Find(v);
 81     }
 82 }
 83 
 84 int main()
 85 {
 86 #ifndef ONLINE_JUDGE
 87     freopen("test.txt","r",stdin);
 88 #endif // ONLINE_JUDGE
 89     scanf("%d",&n);
 90     init();
 91     K=0;
 92     string s1,s2;
 93     int u,v;
 94     int root=-1;
 95     for (int i=1;i<=n;++i)
 96     {
 97         cin>>s1>>s2;
 98         if (names.find(s1)==names.end()){names[s1]=++K;ids[K]=s1;}
 99         if (names.find(s2)==names.end()){names[s2]=++K;ids[K]=s2;}
100         u=names[s1];v=names[s2];
101         addEdge(u,v);
102         addEdge(v,u);
103         if (root==-1 || v==root) root=u;
104     }
105     for (int i=0;i<=K;++i) f[i]=i;
106     scanf("%d",&Q);
107     for (int i=1;i<=Q;++i)
108     {
109         cin>>s1>>s2;
110         u=names[s1];v=names[s2];
111         Qe[i].u=u;Qe[i].v=v;Qe[i].idx=i;Qe[i].ans=-1;
112         g[u].push_back(i);g[v].push_back(i);
113     }
114     memset(vis,0,sizeof(vis));
115     tarjan(root);
116     for (int i=1;i<=Q;++i)
117     {
118         cout<<ids[Qe[i].ans]<<endl;
119     }
120     return 0;
121 }
  1 /*
  2   题意:最近公共祖先
  3   题解:dfs + RMQ_ST实现
  4   时间:2018.07.18
  5 */
  6 
  7 #include <bits/stdc++.h>
  8 using namespace std;
  9 
 10 typedef long long LL;
 11 const int MAXN = 100005;
 12 const LL MOD7 = 1e9+7;
 13 
 14 struct Edge
 15 {
 16     int u,v;
 17     int next;
 18 }edge[4*MAXN];
 19 int head[MAXN];
 20 int cnt;
 21 
 22 map<string,int> names;
 23 map<int,string> ids;
 24 int K;
 25 int n,Q;
 26 
 27 
 28 void init()
 29 {
 30     cnt=0;
 31     memset(head,-1,sizeof(head));
 32 }
 33 
 34 void addEdge(int u,int v)
 35 {
 36     edge[cnt].u=u;edge[cnt].v=v;edge[cnt].next=head[u];head[u]=cnt++;
 37 }
 38 
 39 struct RMQ_ST
 40 {
 41     int a[2*MAXN];
 42     int dp[MAXN][30];
 43     int n;
 44     void init(int n, int a[])
 45     {
 46         this->n = n;
 47         for (int i=1;i<=n;++i) this->a[i] = a[i];
 48         for (int i=1;i<=n;++i) dp[i][0] = i;
 49         for (int j=1;(1<<j)<=n;++j)
 50         {
 51             for (int i=1;i+(1<<j)-1<=n;++i)
 52             {
 53                 dp[i][j] = (a[dp[i][j-1]]<a[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]);
 54             }
 55         }
 56     }
 57     int query(int x,int y)
 58     {
 59         if (x>y) swap(x,y);
 60         int j = log(y-x+1)/log(2);
 61         return (a[dp[x][j]]<a[dp[y-(1<<j)+1][j]]?dp[x][j]:dp[y-(1<<j)+1][j]);
 62     }
 63 }st;
 64 
 65 int ss[MAXN]; // 第一次访问节点的时间
 66 int F[2*MAXN];  // 时间对应的节点
 67 int depth[2*MAXN];   //每个时间对应的深度
 68 int tot;
 69 
 70 void dfs(int u,int pre,int dep)
 71 {
 72     F[++tot]=u;
 73     depth[tot]=dep;
 74     ss[u]=tot;
 75     for (int i=head[u];i!=-1;i=edge[i].next)
 76     {
 77         int v=edge[i].v;
 78         if (v==pre) continue;
 79         dfs(v,u,dep+1);
 80         F[++tot]=u;
 81         depth[tot]=dep;
 82     }
 83 }
 84 
 85 int main()
 86 {
 87 #ifndef ONLINE_JUDGE
 88     freopen("test.txt","r",stdin);
 89 #endif // ONLINE_JUDGE
 90     scanf("%d",&n);
 91     init();
 92     K=0;
 93     string s1,s2;
 94     int u,v;
 95     int root=-1;
 96     for (int i=1;i<=n;++i)
 97     {
 98         cin>>s1>>s2;
 99         if (names.find(s1)==names.end()){names[s1]=++K;ids[K]=s1;}
100         if (names.find(s2)==names.end()){names[s2]=++K;ids[K]=s2;}
101         u=names[s1];v=names[s2];
102         addEdge(u,v);
103         addEdge(v,u);
104         if (root==-1 || v==root) root=u;
105     }
106     tot=0;
107     dfs(root,-1,0);
108     st.init(tot,depth);
109     scanf("%d",&Q);
110     for (int i=1;i<=Q;++i)
111     {
112         cin>>s1>>s2;
113         u=names[s1];v=names[s2];
114         int t = F[st.query(ss[u],ss[v])];
115         cout<<ids[t]<<endl;
116     }
117     return 0;
118 }

 

转载于:https://www.cnblogs.com/LeeSongt/p/9328134.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值