A - Problem E. TeaTree
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.
Input
On 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]<=100000
Output
Your 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 9
题解:
第一次写树上的启发式合并。可以用普通的优化让你n2变成严格nlog,解决一些类似(树上数颜色,树上查众数)这样的问题。这道题,我们先预处理出我们的因数,然后合并的时候判断下。
有的同学可能会有疑问:为什么要清空呢?
由于空间的限制,我们不可能对于每一个节点开一个数组来记录数据,只能开一个全局数组。
在这个全局数组内,如果不清空,就会影响到别的子树,于是导致答案错误。
然而可以发现,统计儿子节点时最后那个节点其实没有必要清空,因为它不再会影响到它的兄弟节点。
这也正是接下来要讲到的优化方法。
思考优化:对于节点x,可以在做子树答案时保留最后一棵子树v的数据不清空,然后统计x的答案时绕过v节点统计别的子树。那么v选哪个呢?当然是选size最大的。
于是,我们得到了一个优化后的做法:对于节点x,先统计轻儿子的答案,并将它们的数据清除;然后统计重儿子的答案,保留数据;最后遍历其他轻儿子及其子树,把它们的数据与重儿子合并。
#include <bits/stdc++.h>
//#define int long long
typedef long long ll;
using namespace std;
const int N=200005;
set<int> st[N];
vector<int> g[N];
int ans[N];
int ne[N<<1],head[N<<1],cnt,e[N<<1],w[N];
void add(int a,int b)
{
e[cnt]=b,ne[cnt]=head[a],head[a]=cnt++;
}
int Merge(int u,int v)
{
int res=-1;
if(st[u].size()<st[v].size()) swap(st[u],st[v]);
for(auto it:st[v]){
if(st[u].count(it)) res=max(res,it);
else st[u].insert(it);
}
st[v].clear();
return res;
}
void dfs(int u)
{
for(int i=head[u];~i;i=ne[i]){
int j=e[i];
dfs(j);
ans[u]=max(ans[u],Merge(u,j));
}
for(auto it:g[w[u]]){
if(st[u].count(it)){
ans[u]=max(ans[u],it);
}else st[u].insert(it);
}
}
int main()
{
for(int i=1;i<N;i++){
for(int j=i;j<N;j+=i){
g[j].push_back(i);
}
}
int n;
while(cin>>n) {
cnt=0;
memset(ans, -1, sizeof ans);
memset(head, -1, sizeof head);
for (int i = 2; i <= n; i++) {
int tmp;
scanf("%d", &tmp);
add(tmp, i);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
}
dfs(1);
for (int i = 1; i <= n; i++) printf("%d\n", ans[i]);
for(int i=1;i<N;i++) {
st[i].clear();
}
}
}