标签:const root nta return vector shu first div max
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\n", 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\n", ans[i]);
return 0;
}
标签:const root nta return vector shu first div max
原文地址:https://www.cnblogs.com/ccut-ry/p/9733752.html