大致题意:
给出一棵根树,给出一些成对的点,求出每对点的最近公共祖先。
大致思路:
第一道Tarjan,很裸,这个题目算是当模版用了,代码修改自 子任博客
给出一棵根树,给出一些成对的点,求出每对点的最近公共祖先。
大致思路:
第一道Tarjan,很裸,这个题目算是当模版用了,代码修改自 子任博客
详细代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 1100
#define MAXM 500000
struct Edge{
int u,v,next;
} e[2*MAXN];
struct Query{
int u,v,w,next;
} e1[MAXM];
int n, m, cnt1, cnt2;
int head1[MAXN], head2[MAXN], parent[MAXN], ans[MAXM], ret[MAXN];
bool vis[MAXN];
bool use[MAXN];
void init(){
cnt1 = cnt2 = 1;
memset(head1,-1,sizeof(int)*(n+1));
memset(head2,-1,sizeof(int)*(n+1));
memset(vis,false,sizeof(bool)*(n+1));
memset(parent,-1,sizeof(int)*(n+1));
}
void addedge(int u, int v){
e[cnt1].u = u;
e[cnt1].v = v;
e[cnt1].next = head1[u];
head1[u] = cnt1++;
}
void addedge2(int u,int v,int w){
e1[cnt2].u = u;
e1[cnt2].v = v;
e1[cnt2].w = w;
e1[cnt2].next = head2[u];
head2[u] = cnt2++;
}
int find(int u){
if(parent[u] == -1)
return u;
return parent[u] = find(parent[u]);
}
void tarjan(int u){
int i, v, w;
vis[u] = true;
for(i = head2[u]; i != -1; i = e1[i].next){
v = e1[i].v;
w = e1[i].w;
if(vis[v])
ans[w] = find(v);
}
for(i = head1[u]; i != -1; i = e[i].next){
v = e[i].v;
if(!vis[v]){
tarjan(v);
parent[v] = u;
}
}
}
int main(){
int i, j, u, v;
while(scanf("%d",&n) != -1){
init();
memset(use,false,sizeof(bool)*(n+1));
for(i = 1; i <= n; i++){
scanf("%d:",&u);
while(getchar() != '(');
scanf("%d",&j);
while(getchar() != ')');
while(j--){
scanf("%d",&v);
addedge(u,v);
use[v] = true;
}
}
scanf("%d",&m);
for(i = 1; i <= m; i++){
while(getchar() != '(');
scanf("%d%d",&u,&v);
addedge2(u,v,i);
addedge2(v,u,i);
while(getchar() != ')');
}
for(i = 1; i <= n; i++) //寻找根节点,这里是trick
if(!use[i])
break;
tarjan(i);
sort(ans+1,ans+m+1); ////ans[i]用来存放第i问中两点的公共祖先
memset(ret,0,sizeof(ret));
for(i = 1; i <= m; i++){
ret[ans[i]]++;
}
for(i =1; i <= n; i++)
if(ret[i]!= 0)printf("%d:%d\n",i,ret[i]);
}
return 0;
}