[LOJ]#6159. 「美团 CodeM 初赛 Round A」最长树链 点分治

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/85330293

Description:

Mr. Walker 最近在研究树,尤其是最长树链问题。现在树中的每个点都有一个值,他想在树中找出最长的链,使得这条链上对应点的值的最大公约数不等于1。请求出这条最长的树链的长度。

题解:

我的做法大概是最差的……不过是我自己想的。
点分治,对于每个重心找经过它的路径答案,设 f i f_i 表示最大公约数为 i i 倍数的最大深度,由于每个数不同的质因数不会超过 10 10 个,所以每到一个点可以暴力更新它所含有的质因数的 f f ,这样复杂度是 O ( 10 n log n ) O(10n\log n)
正解是枚举质因数,然后把含有该质因数的点设为 1 1 后找树的直径,由于每个点只会在枚举到它的质因数时被访问一次,所以复杂度为所有数的质因数个数和,十分优秀,可惜我没有想到。
一开始TLE的怀疑人生……一度想去膜题解,还好最后发现是点分治打错了,不要轻易放弃。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,a[Maxn],ans=1;
unordered_map<int,int> f;
int gcd(int a,int b)
{
	if(!a)return b;
	return gcd(b%a,a);
}
vector<int>p[Maxn],pp[Maxn];
vector<pa>tmp;
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y)
{
	int t=++len;
	e[t].y=y;e[t].next=last[x];last[x]=t;
}
int prime[4000],lp=0;bool mark[32000];
void pre()
{
	for(int i=2;i<31622;i++)
	{
		if(!mark[i])prime[++lp]=i;
		for(int j=1;prime[j]*i<31622&&j<=lp;j++)
		{
			mark[prime[j]*i]=true;
			if(i%prime[j]==0)break;
		}
	}
}
bool vis[Maxn];int root=0,son[Maxn],tot;
int get_root(int x,int fa)
{
	int sz=1,mx=0;
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==fa||vis[y])continue;
		int t=get_root(y,x);
		sz+=t;mx=max(mx,t);
	}
	son[x]=max(mx,tot-sz);
	if(son[x]<son[root])root=x;
	return sz;
}
int get_size(int x,int fa)
{
	int sz=1;
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==fa||vis[y])continue;
		sz+=get_size(y,x);
	}
	return sz;
}
void DFS(int v,int x,int fa,int op,int dep)
{
	if(op==1)
	{
		tmp.push_back(make_pair(x,dep));
		for(int i=0;i<pp[x].size();i++)
		ans=max(ans,dep+1+f[pp[x][i]]);
	}
	else
	{
		for(int i=0;i<pp[x].size();i++)
		f[pp[x][i]]=0;
	}
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==fa||vis[y])continue;
		int t=gcd(a[x],a[y]);
		if(t==1)continue;
		pp[y].clear();
		if(pp[x].size()<p[y].size())
		{
			for(int j=0;j<pp[x].size();j++)
			if(t%pp[x][j]==0)pp[y].push_back(pp[x][j]);
		}
		else
		{
			for(int j=0;j<p[y].size();j++)
			if(t%p[y][j]==0)pp[y].push_back(p[y][j]);
		}
		DFS(t,y,x,op,dep+1);
	}
}
void work(int x,int op)
{
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(vis[y])continue;
		int t=gcd(a[x],a[y]);
		if(t==1)continue;
		pp[y].clear();tmp.clear();
		if(p[x].size()<p[y].size())
		{
			for(int j=0;j<p[x].size();j++)
			if(t%p[x][j]==0)pp[y].push_back(p[x][j]);
		}
		else
		{
			for(int j=0;j<p[y].size();j++)
			if(t%p[y][j]==0)pp[y].push_back(p[y][j]);
		}
		DFS(t,y,x,op,1);
		for(int j=0;j<tmp.size();j++)
		for(int k=0;k<pp[tmp[j].first].size();k++)
		f[pp[tmp[j].first][k]]=max(f[pp[tmp[j].first][k]],tmp[j].second);
	}
}
void dfs(int x)
{
	vis[x]=true;
	work(x,1);work(x,-1);
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(vis[y])continue;
		tot=get_size(y,x);
		if(tot<=ans)continue;
		root=0;get_root(y,x);dfs(root);
	}
}
int main()
{
	pre();son[0]=inf;
	n=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++)
	{
		int x=read();
		a[i]=x;
		for(int j=1;prime[j]*prime[j]<=a[i]&&j<=lp;j++)
		if(x%prime[j]==0)
		{
			p[i].push_back(prime[j]);
			while(x%prime[j]==0)x/=prime[j];
		}
		if(x!=1)p[i].push_back(x);
	}
	tot=n;get_root(1,0);dfs(root);
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/85330293