题目链接

bitset优化

题意:给一棵树,树上每个节点都有一个权值,问每一个节点任取两个子节点的gcd值最大是多少。

解法:
每一个节点设置一个bitset,用来存储节点权值的所有因子,如果因子为x,则在bitset的第x为设置为1。
只要知道每一个子节点存储权值的bitset,就能通过 & 得到共有的因子,而最大的那个因子就是最大的gcd值,合并子节点的bitset可以通过 | 运算符操作,因为bitset有一个函数 _Find_first() 能返回bitset中最低位为1的下标,所以把要存的因子的值x,取反 Maxn-x来存储,通过函数_Find_first()就能快速找出最大的因子是多少。bitset的位运算时间复杂度是log级别的,所以总的时间复杂度是 n\(\times\)\(\sqrt[2]{n}\)\(\times\)\(\log_2{n}\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <bitset>
#include <cstdlib>

using namespace std;

const int Maxn = 1e5+10;
const int INF = 0x3f3f3f3f;

vector <int> G[Maxn];
int v[Maxn], ans[Maxn];

bitset <Maxn> dfs(int x) {
	bitset <Maxn> b1, b2;
	for(int i = 1; i*i <= v[x]; ++i) {
		if(v[x]%i == 0) b1[Maxn-i] = b1[Maxn-v[x]/i] = 1;
	}
	int len = G[x].size(), res = -1;
	for(int i = 0; i < len; ++i) {
		int v = G[x][i];
		b2 = dfs(v);
		res = max(res, (int)(Maxn-(b1&b2)._Find_first()));
		b1 |= b2;
	}
	ans[x] = res;
	return b1;
}

int main(void)
{
	int n;
	scanf("%d", &n);
	int tmp;
	for(int i = 2; i <= n; ++i) {
		scanf("%d", &tmp);
		G[tmp].push_back(i);
	}
	for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
	dfs(1);
	for(int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
	return 0;
 }