题目描述:点击打开链接
题目大意:
给定一棵树和一些询问,求每个询问的LCA,打印每个节点在询问中是LCA的次数。
输入的第一行是结点个数n,接下来的n行中,第一个数是描述的节点,括号中是该节点的儿子的个数,在后面的数是该节点的儿子。然后是一个数m,代表询问的个数,后面是形如(x,y)的询问,就是问x和y的LCA。
输出是 节点:次数 的格式,是每个节点是LCA的次数。
这题就是用tarjan算法求LCA。
我犯了这些错误:
1、询问可能会重复,所以在记录时要记录它的出现次数。
2、输入时随心所欲的空格让我错了很久,在网上看了题解,借用了一下输入方法。然后就因输入时多加了一个getchar()让我WA了一个小时。
代码:
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
vector<int> a[905];
int que[905][905]= {0};
int fa[905]= {0};
int find(int x) {
if(fa[x]==0) {
return x;
}
return fa[x]=find(fa[x]);
}
int use[905]= {0};
int ans[905]= {0};
void lca(int x) {
for(int i=0; i<a[x].size(); i++) {
lca(a[x][i]);
fa[a[x][i]]=x;
}
use[x]=true;
for(int i=1; i<=n; i++) {
if(use[i]&&que[x][i]) {
ans[find(i)]+=que[x][i];
}
}
return ;
}
int main() {
while(scanf("%d",&n)!=EOF) {
memset(fa,0,sizeof(fa));
memset(use,0,sizeof(use));
memset(que,0,sizeof(que));
memset(ans,0,sizeof(ans));
for(int i=1; i<=n; i++) {
a[i].clear();
}
bool root[905]= {0};
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);
a[x].push_back(z);
root[z]=true;
}
}
scanf("%d",&m);
for(int i=1; i<=m; i++) {
int x,y;
char xx;
scanf(" (%d %d)",&x,&y);
que[x][y]++,que[y][x]++;
}
for(int i=1; i<=n; i++) {
if(root[i]==false) {
lca(i);
break;
}
}
for(int i=1; i<=n; i++) {
if(ans[i]) {
printf("%d:%d\n",i,ans[i]);
}
}
}
return 0;
}