题意
给你一个树,每个点有个权值v[i]。
每两个点i, j会告诉他们的LCA一个值gcd(v[i], v[j])。
现在问每个点所听到的最大的值。
n <= 1e5, v[i] <= 1e5
题解
树上启发式合并。
对于每个节点,用set记录它的子树存在哪些因子, 取所有出现两次的因子的max。
要求出这个set,我们对于它所有的儿子的set,看哪个大,每次把小的一个set里的数一一插入到大的set里面去,同时判断大的set里面是否已经存在这个数,如果存在,这个节点的ans对这个数取max。
注意合并之后原来的set要clear掉,这样省空间也省时间。
还可以用unordered_set加速。
复杂度
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <bitset>
#include <map>
#include <vector>
#include <set>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MOD = 998244353;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MAXN = 1e5 + 5;
const int mod = 998244353;
int f[MAXN], v[MAXN];
struct Edge {
int v, nxt;
} e[MAXN];
int head[MAXN], tot;
void add (int x, int y) {
e[tot] = {y, head[x]};
head[x] = tot++;
}
int ans[MAXN];
set<int> s[MAXN];
int tran[MAXN];
void dfs (int now) {
tran[now] = now;
for (int i = head[now]; ~i; i = e[i].nxt) {
dfs (e[i].v);
if (s[tran[e[i].v]].size() < s[tran[now]].size() ) {
for (int p : s[tran[e[i].v]]) {
if (s[tran[now]].count (p) ) ans[now] = max (ans[now], p);
else s[tran[now]].insert (p);
}
s[tran[e[i].v]].clear();
} else {
for (int p : s[tran[now]]) {
if (s[tran[e[i].v]].count (p) ) ans[now] = max (ans[now], p);
else s[tran[e[i].v]].insert (p);
}
s[tran[now]].clear();
tran[now] = tran[e[i].v];
}
}
for (int i = 1; i * i <= v[now]; i++) {
if (v[now] % i == 0) {
if (s[tran[now]].count (i) ) ans[now] = max (ans[now], i);
else s[tran[now]].insert (i);
if (i * i != v[now]) {
if (s[tran[now]].count (v[now] / i) ) ans[now] = max (ans[now], v[now] / i);
else s[tran[now]].insert (v[now] / i);
}
}
}
}
int read() {
int x = 0;
char c = getchar();
while (c < '0' || c > '9')c = getchar();
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
int main() {
#ifdef LOCAL
freopen ("input.txt", "r", stdin);
#endif
int n;
n = read();
memset (head, -1, sizeof (head) );
memset (ans, -1, sizeof (ans) );
for (int i = 2; i <= n; i++) {
f[i] = read();
add (f[i], i);
}
for (int i = 1; i <= n; i++) v[i] = read();
dfs (1);
for (int i = 1; i <= n; i++) printf ("%d\n", ans[i]);
return 0;
}