题目链接:我是链接!!
题意:给一颗以1为根节点的树,每个节点有一个权值,计算每个节点以当前节点为最近公共祖先的节点对gcd中的最大值。
分析:数据量是100000,如果两两枚举计算的话不管怎么样是肯定会T的,所以从每个数考虑。预处理出每个数的所有因子,最大数为100000,每个数的因子数不会大于400个。根据每个节点的权值,可以得到每个节点的因数集合。然后进行dfs,将每个节点的因数集合与它的儿子的因数集合合并,合并的过程中就可以计算因数集合中最大的相同的数,也就是我们要求的gcd的最大值。
因数集合的保存和合并有两种方式,第一种是用vector存因数,每次直接利用类似于归并排序中合并的方法进行暴力合并。另一种是用权值线段树,每次合并就合并两颗树。第一种大概跑了1000ms,第二种方法跑了2600ms。(数据结构什么的不存在的)
代码:
vector暴力合并
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 100000 + 5;
const int mx = 100000;
int n;
vector<int>g[N];
vector<int>di[N];
vector<int>hav[N];
int ans[N];
void init()
{
for(int i = 1; i <= mx; i++)
{
for(int j = i; j <= mx; j += i)
{
di[j].push_back(i);
}
}
}
void merge(int x,int v)
{
int i = 0, j = 0;
vector<int>tem;
for(; i < hav[x].size() && j < hav[v].size();)
{
int a1 = hav[x][i], a2 = hav[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 < hav[x].size(); i++)tem.push_back(hav[x][i]);
for(; j < hav[v].size(); j++)tem.push_back(hav[v][j]);
hav[x] = tem;
return;
}
void dfs(int x)
{
ans[x] = -1;
for(int i = 0; i < g[x].size(); i++)
{
int v = g[x][i];
dfs(v);
merge(x,v);
}
return;
}
int main()
{
init();
scanf("%d",&n);
for(int i = 2; i <= n; i++)
{
int a; scanf("%d",&a);
g[a].push_back(i);
}
for(int i = 1; i <= n; i++)
{
int val; scanf("%d",&val);
hav[i] = di[val];
}
dfs(1);
for(int i = 1; i <= n; i++) printf("%d\n",ans[i]);
return 0;
}
权值线段树合并
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 100000 + 5;
const int mx = 100000;
int n;
vector<int>g[N];
vector<int>di[N];
int ans[N];
void init()
{
for(int i = 1; i <= mx; i++)
{
for(int j = i; j <= mx; j += i)
{
di[j].push_back(i);
}
}
}
int root[N], tot = 0;
int lson[N*400],rson[N*400],maxx[N*400];
void pushup(int d)
{
if(lson[d] && rson[d]) maxx[d] = max(maxx[lson[d]],maxx[rson[d]]);
else if(lson[d]) maxx[d] = maxx[lson[d]];
else if(rson[d]) maxx[d] = maxx[rson[d]];
return;
}
void update(int &d,int l,int r,int p)
{
if(d == 0) d = ++tot;
if(l == r)
{
maxx[d] = p;
return ;
}
int m = (l+r) >> 1;
if(p <= m) update(lson[d],l,m,p);
else update(rson[d],m+1,r,p);
pushup(d);
return;
}
int merge(int rt,int srt,int x)
{
if(rt == 0 || srt == 0) return rt^srt;
if(maxx[rt] == maxx[srt]) ans[x] = max(ans[x],maxx[rt]);
if(lson[rt] || lson[srt]) lson[rt] = merge(lson[rt],lson[srt],x);
if(rson[rt] || rson[srt]) rson[rt] = merge(rson[rt],rson[srt],x);
pushup(rt);
return rt;
}
void dfs(int x)
{
ans[x] = -1;
for(int i = 0; i < g[x].size(); i++)
{
int v = g[x][i];
dfs(v);
root[x] = merge(root[x],root[v],x);
}
return;
}
int main()
{
init();
tot = 0;
scanf("%d",&n);
for(int i = 2; i <= n; i++)
{
int a; scanf("%d",&a);
g[a].push_back(i);
}
for(int i = 1; i <= n; i++)
{
int val; scanf("%d",&val);
root[i] = 0;
for(int j = 0; j < di[val].size();j++)
{
update(root[i],1,mx,di[val][j]);
}
}
dfs(1);
for(int i = 1; i <= n; i++) printf("%d\n",ans[i]);
return 0;
}