牛客挑战赛42 小睿睿的伤害
树上启发式合并
枚举每个数字的所有因子,存起来
官方题解传送门 https://ac.nowcoder.com/discuss/485120?type=101&order=0&pos=2&page=1&channel=-1&source_id=1
题目传送门 https://ac.nowcoder.com/acm/contest/6944/B
具体看代码吧,有注释
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
const int maxn = 1e5 + 100;
typedef long long ll;
vector<int>G[maxn];
void add(int be, int en) {
G[be].push_back(en);
}
int siz[maxn];
int son[maxn];
int dfs(int x, int fa) {
siz[x] = 1;
int c = 0;
for (int p : G[x]) {
if (p == fa) continue;
dfs(p, x);
siz[x] += siz[p];
if (siz[p] > c) {
c = siz[p];
son[x] = p;
}
}
return 0;
}
ll ans[maxn];//最大约数
ll num[maxn];//有num对
ll cnt[maxn];//公共资源,p这个数字是cnt【p】个数字的因子
int list[maxn];
vector<int>ins[maxn];
int cal(int x, int fa, int f) {//计算cnt,f是1就是加,f=-1就是清除答案
for (int p : ins[list[x]]) cnt[p] += f;
for (int p : G[x]) {
if (p == fa) continue;
cal(p, x, f);
}
return 0;
}
int cal_ans(int x, int fa,int f,ll &cn,ll &an) {//重儿子算过了,只算轻儿子,cn和an就是cnt[x]和ans[x]
for (int p : ins[list[x]]) {
if (cnt[p]) {
if (p > an) {
an = p;
cn = cnt[p];
}
else if(p == an){
cn += cnt[p];
}
}
}
for (int p : G[x]) {
if (p == fa || p == f) continue;
cal_ans(p, x, f, cn, an);
}
return 0;
}
int dfs2(int x, int fa, int flag) {
for (int p : G[x]) {
if (p == fa) continue;
if (p == son[x]) continue;
dfs2(p, x, 0);
}
if (son[x] != 0) {
dfs2(son[x], x, 1);
}
//num[x] = ans[x] = 0;
for (int p : G[x]) {
if (p == fa || p == son[x]) continue;
cal_ans(p, x, son[x], num[x], ans[x]);
cal(p, x, 1);
}
for (int p : ins[list[x]]) {
if (cnt[p]) {
if (p > ans[x]) {
ans[x] = p;
num[x] = cnt[p];
}
else if(p == ans[x]){
num[x] += cnt[p];
}
}
cnt[p]++;
}
if (flag == 0) {
cal(x, fa, -1);
}
return 0;
}
int main() {
for (int i = 1; i < maxn; i++) {
for (int j = 1; j*i < maxn; j++) {
ins[i*j].push_back(j);//i*j的所有因子由j组成
}
}
int n;
int x, y;
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
scanf("%d %d", &x, &y);
add(x, y);
add(y, x);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &list[i]);
}
dfs(1, -1);//找重儿子
dfs2(1, -1, 0);//启发式合并
for (int i = 1; i <= n; i++) {
printf("%lld %lld\n", ans[i], num[i]);
}
return 0;
}
寻找真正的热爱

浙公网安备 33010602011771号