现有一棵由n个节点组成的无向树,节点按从0到n - 1编号。输入一个整数n和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi, wi] 表示树中存在一条位于节点 ui 和节点 vi 之间、权重为 wi 的边。
另给你一个长度为 m 的二维整数数组 queries ,其中 queries[i] = [ai, bi] 。对于每条查询,请你找出使从 ai 到 bi 路径上每条边的权重相等所需的 最小操作次数 。在一次操作中,你可以选择树上的任意一条边,并将其权重更改为任意值。
注意:
查询之间 相互独立 的,这意味着每条新的查询时,树都会回到 初始状态 。
从 ai 到 bi的路径是一个由 不同 节点组成的序列,从节点 ai 开始,到节点 bi 结束,且序列中相邻的两个节点在树中共享一条边。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是第 i 条查询的答案。
n为节点数,edges为存在边的两个节点之间的距离,queries表示的两节点间有一条路径,其中每边长度可能不同,修改最少次数让每边相等。
以节点0为根节点,使用数组count[i]
记录节点i到根节点0的路径上边权重的数量,即count[i][j]
表示节点i到根节点0的路径上权重为j的边数量。对于查询queries[i]=[ai,bi]
,记节点lcai为节点ai与bi的最近公共祖先,那么从节点ai到节点bi的路径上,权重为j的边数量tj的计算如下:
tj=count[ai][j]+count[bi][j]−2×count[lcai][j]
为了让节点 ai到节点 bi路径上每条边的权重都相等,贪心地将路径上所有的边都更改为边数量最多的权重即可,即从节点 ai到节点 bi路径上每条边的权重都相等所需的最小操作次数 resi的计算如下:
resi=∑j=1Wtj−max1≤j≤Wtj
其中W=26表示权重的最大值。
最近公共祖先节点的求解可以采用Tarjan算法。
const int W = 26;
typedef struct Node {
int node;
int index;
struct Node *next;
} Node;
typedef struct {
int key;
int val;
UT_hash_handle hh;
} HashItem;
Node *creatNode(int node, int index) {
Node *obj = (Node *)malloc(sizeof(Node));
obj->node = node;
obj->index = index;
obj->next = NULL;
return obj;
}
HashItem *hashFindItem(HashItem **obj, int key) {
HashItem *pEntry = NULL;
HASH_FIND_INT(*obj, &key, pEntry);
return pEntry;
}
bool hashAddItem(HashItem **obj, int key, int val) {
if (hashFindItem(obj, key)) {
return false;
}
HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));
pEntry->key = key;
pEntry->val = val;
HASH_ADD_INT(*obj, key, pEntry);
return true;
}
bool hashSetItem(HashItem **obj, int key, int val) {
HashItem *pEntry = hashFindItem(obj, key);
if (!pEntry) {
hashAddItem(obj, key, val);
} else {
pEntry->val = val;
}
return true;
}
int hashGetItem(HashItem **obj, int key, int defaultVal) {
HashItem *pEntry = hashFindItem(obj, key);
if (!pEntry) {
return defaultVal;
}
return pEntry->val;
}
void hashFree(HashItem **obj) {
HashItem *curr = NULL, *tmp = NULL;