// 3452K 719MS C++
#include <cstdio>
#include <cstring>
const int MAX = 910;
struct TreeNode {
int NextBroId;
int parentId;
};
typedef struct TreeNode TreeNode;
int LCACounter[MAX];
int querys[MAX][MAX];
int childListHead[MAX];
int UF_Ancestor[MAX];
int queryNum;
int caseNum;
int nodeNum;
TreeNode tree[MAX];
int ancestor[MAX];
char fullyVisited[MAX];
int querySolvedNum;
void insertIntoChildList(int parentId, int childId) {
tree[childId].parentId = parentId;
int prevChildListHeadId = childListHead[parentId];
tree[childId].NextBroId = prevChildListHeadId;
childListHead[parentId] = childId;
}
inline int UF_find(int nodeId) {
// printf("UF_find %d\n", nodeId);
int parentNodeUFId = nodeId;
if (UF_Ancestor[parentNodeUFId] != parentNodeUFId) {
UF_Ancestor[nodeId] = UF_find(UF_Ancestor[parentNodeUFId]);
return UF_Ancestor[nodeId];
} else {
return parentNodeUFId;
}
}
inline void UF_Merge(int parentId, int childId) {
int parentUFId = UF_find(parentId);
int childUFId = UF_find(childId);
UF_Ancestor[childUFId] = parentUFId;
UF_Ancestor[childId] = parentUFId;
}
int DFSWithUF(int curNodeId) {
// printf("DFSWithUF %d\n", curNodeId);
UF_Ancestor[curNodeId] = curNodeId;
// ancestor[curNodeId] = curNodeId;
int curChildNodeId = childListHead[curNodeId];
while(curChildNodeId) {
if (DFSWithUF(curChildNodeId)) {
return 1;
}
UF_Merge(curNodeId, curChildNodeId);
// ancestor[UF_find(curNodeId)] = curNodeId;
curChildNodeId = tree[curChildNodeId].NextBroId;
}
// printf("%d is Ved\n", curNodeId);
fullyVisited[curNodeId] = 1;
for (int i = 1; i <= querys[curNodeId][0]; i++) {
if (fullyVisited[querys[curNodeId][i]]) {
int res = UF_Ancestor[UF_find(querys[curNodeId][i])];
LCACounter[res]++;
// printf("FIND %d %d %d %d\n", curNodeId,
// querys[curNodeId][i], res, UF_Ancestor[querys[curNodeId][i]]);
querySolvedNum++;
if (querySolvedNum == queryNum) {
return 1;
}
}
}
return 0;
}
int main() {
while(scanf("%d", &nodeNum) != EOF) {
memset(childListHead, 0, sizeof(childListHead));
memset(tree, 0, sizeof(tree));
memset(UF_Ancestor, 0, sizeof(UF_Ancestor));
memset(LCACounter, 0, sizeof(LCACounter));
memset(querys, 0, sizeof(querys));
memset(fullyVisited, 0, sizeof(fullyVisited));
memset(ancestor, 0, sizeof(ancestor));
querySolvedNum = 0;
for (int nodeId = 1; nodeId <= nodeNum; nodeId++) {
int parentId;
int childId;
int childNum;
scanf("%d", &parentId);
// scanf("%s", nodeInfo);
while(getchar() != '(');
scanf("%d", &childNum);
while(getchar() != ')');
// parentId = nodeInfo[0] - '0';
// int childNum = nodeInfo[3] - '0';
for (int j = 0; j < childNum; j++) {
scanf("%d", &childId);
// printf("%d Child %d\n", parentId, childId);
insertIntoChildList(parentId, childId);
}
}
scanf("%d", &queryNum);
for (int i = 1; i <= queryNum; i++) {
int A, B;
while(getchar() != '(');
scanf("%d%d", &A, &B);
while(getchar() != ')');
querys[A][0]++;
querys[A][querys[A][0]] = B;
querys[B][0]++;
querys[B][querys[B][0]] = A;
}
int rootNodeId = 0;
for (int i = 1; i <= nodeNum; i++) {
if (tree[i].parentId == 0) {
rootNodeId = i;
break;
}
}
DFSWithUF(rootNodeId);
for (int i = 1; i <= nodeNum; i++) {
if (LCACounter[i] > 0) {
printf("%d:%d\n", i, LCACounter[i]);
}
}
}
}
刚搞完1330以后趁热打铁, 原理一样,都是LCA, 只不过这次会有很多的query,因此,如果每次dfs都遍历所有的query的话,基本就TLE了,
因此要搞一个二维矩阵来标示query, query[i][j] 表示与 i 包含在相同query的 第j-1个(query[i][0]表示与i相关的query的数量)node的Id, 每次读入一个query,取到两个点A,B
就更新A 和 B的query矩阵,然后在dfs完某个点k以后,就只遍历query[k][1...N]就可以了,
这里还发现了之前的1330的一个错误,没有加dfs的访问标记vist[], 在每次dfs完某个点以后,就要标示已经visted, 然后下边判断是否是LCA的时候要用是否visted作为标准。
被注释掉的ancsteor数组是为了平衡并查集使用的,如果用平衡并查集的话,一个集合的root不一定就是 此集合在树中的根节点。不过如果不使用平衡并查集的话 ,而是直接根据树的结构来合并集合的话,就没有关系.