Recently, TeaTree acquire new knoledge gcd (Greatest Common Divisor), now she want to test you.
As we know, TeaTree is a tree and her root is node 1, she have n nodes and n-1 edge, for each node i, it has it’s value v[i].
For every two nodes i and j (i is not equal to j), they will tell their Lowest Common Ancestors (LCA) a number : gcd(v[i],v[j]).
For each node, you have to calculate the max number that it heard. some definition:
In graph theory and computer science, the lowest common ancestor (LCA) of two nodes u and v in a tree is the lowest (deepest) node that has both u and v as descendants, where we define each node to be a descendant of itself.
As we know, TeaTree is a tree and her root is node 1, she have n nodes and n-1 edge, for each node i, it has it’s value v[i].
For every two nodes i and j (i is not equal to j), they will tell their Lowest Common Ancestors (LCA) a number : gcd(v[i],v[j]).
For each node, you have to calculate the max number that it heard. some definition:
In graph theory and computer science, the lowest common ancestor (LCA) of two nodes u and v in a tree is the lowest (deepest) node that has both u and v as descendants, where we define each node to be a descendant of itself.
InputOn the first line, there is a positive integer n, which describe the number of nodes.
Next line there are n-1 positive integers f[2] ,f[3], …, f[n], f[i] describe the father of node i on tree.
Next line there are n positive integers v[2] ,v[3], …, v[n], v[i] describe the value of node i.
n<=100000, f[i]<i, v[i]<=100000OutputYour output should include n lines, for i-th line, output the max number that node i heard.
For the nodes who heard nothing, output -1.Sample Input
4 1 1 3 4 1 6 9Sample Output
2 -1 3 -1
题意 : 给你一颗树,求以任意一个点为根节点时,该子树内最大的 gcd 是多少,并且所求gcd的两个点的 lca 等于根节点
思路分析 : 1 . 用 vector 模拟归并排序,预处理一下每个数字的约数有哪些,然后合并就可以了
#define ll long long const int maxn = 1e5+5; int n; vector<int>d[maxn], ve[maxn], f[maxn]; void init(){ for(int i = 1; i <= 100000; i++){ for(int j = i; j <= 100000; j += i){ d[j].push_back(i); } } } int val[maxn], ans[maxn]; vector<int>temp; void merge(int x, int y){ temp.clear(); if (f[x].size() == 0) f[x] = d[val[x]]; if (f[y].size() == 0) f[y] = d[val[y]]; int i = 0, j = 0; while((i < f[x].size()) && (j < f[y].size())){ if (f[x][i] < f[y][j]) temp.push_back(f[x][i]), i++; else if (f[x][i] > f[y][j]) temp.push_back(f[y][j]), j++; else { temp.push_back(f[x][i]); ans[x] = max(ans[x], f[x][i]); i++, j++; } } while (i < f[x].size()) { temp.push_back(f[x][i]); i++; } while(j < f[y].size()) { temp.push_back(f[y][j]); j++; } f[x].clear(); f[y].clear(); f[x] = temp; } void merge8(int x,int v) { int i = 0, j = 0; vector<int>tem; for(; i < f[x].size() && j < f[v].size();) { int a1 = f[x][i], a2 = f[v][j]; if(a1 < a2) { tem.push_back(a1); i++; } else if(a1 == a2) { ans[x] = max(ans[x],a1); tem.push_back(a1); i++;j++; } else { tem.push_back(a2); j++; } } for(; i < f[x].size(); i++)tem.push_back(f[x][i]); for(; j < f[v].size(); j++)tem.push_back(f[v][j]); f[x] = tem; return; } void dfs(int x){ for(int i = 0; i < ve[x].size(); i++){ int to = ve[x][i]; dfs(to); merge(x, to); } } int main() { init(); cin >> n; int x; memset(ans, -1, sizeof(ans)); for(int i = 2; i <= n; i++){ scanf("%d", &x); ve[x].push_back(i); } for(int i = 1; i <= n; i++){ scanf("%d", &val[i]); //f[i] = d[val[i]]; } dfs(1); for(int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }
2 . 对每个权值建立一颗权值线段树,10万以内的数不同的约数最多有 400 个,然后将线段树两两合并即可
代码示例 :
#define ll long long const int maxn = 1e5+5; int n; vector<int>ve[maxn], d[maxn]; int root[maxn], cnt = 1; int lson[maxn*400], rson[maxn*400], maxx[maxn*400]; void init(){ for(int i = 1; i <= 100000; i++){ for(int j = i; j <= 100000; j += i) d[j].push_back(i); } } void pushup(int k){ if (lson[k] && rson[k]) maxx[k] = max(maxx[lson[k]], maxx[rson[k]]); else if (lson[k]) maxx[k] = maxx[lson[k]]; else if (rson[k]) maxx[k] = maxx[rson[k]]; } void update(int &rt, int l, int r, int num){ if (!rt) rt = cnt++; if (l == r) { maxx[rt] = num; return; } int mid = (l+r)>>1; if (num <= mid) update(lson[rt], l, mid, num); else update(rson[rt], mid+1, r, num); pushup(rt); } int merge(int x, int y, int &ans){ if (!x || !y) return x^y; if (maxx[x] == maxx[y]) ans = max(ans, maxx[x]); if (lson[x] || lson[y]) lson[x] = merge(lson[x], lson[y], ans); if (rson[x] || rson[y]) rson[x] = merge(rson[x], rson[y], ans); pushup(x); return x; } int ans[maxn]; void dfs(int x){ ans[x] = -1; for(int i = 0; i < ve[x].size(); i++){ int to = ve[x][i]; dfs(to); root[x] = merge(root[x], root[to], ans[x]); } } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int x; init(); cin >> n; for(int i = 2; i <= n; i++){ scanf("%d", &x); ve[x].push_back(i); } int val; for(int i = 1; i <= n; i++){ root[i] = 0; scanf("%d", &val); for(int j = 0; j < d[val].size(); j++){ update(root[i], 1, 100000, d[val][j]); } } dfs(1); for(int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }