[CodeForeces842]Ilya And The Tree解题报告(因数分解)
传送门:不要戳我QAQ
这道题是昨天晚上模拟赛的第二题。一下子没冷静就写了一坨树剖,没调出来,最后交一个n3的暴力然后爆零了。
考虑到每个节点的最后答案都是从这个节点到根节点的一条链,并且每个节点都要有答案。所以不应该考虑树链剖分而应该考虑树形dp。
每个节点最后的答案链都必然交与根节点,这意味着我们的答案有两种情况:取了根节点和没取根节点。没取根节点的情况很好维护,用普通的dfs就搞定了,这里不细解释,不明白看代码就懂了。
对于取根节点的情况,我们这样考虑,既然取了根节点,那么最后答案必然是根节点权值的因子,因为gcd的第一个数就是根节点的权值。我们维护一个数组num[x],表示我们做树形dp的dfs时,当前结点到根节点的路径上所有节点包含的根节点的因子的个数。简单点说就是,根节点的因子在路上出现的次数。对于一个节点,如果它要取一个答案x,那么x必须满足两个条件,1,该节点权值被x整除,2,x在该节点到根的路上出现了至少depth-1(该节点深度)次。(depth-1)次就能做到去掉一个节点后该值能整除所有节点。
那么代码实现就很简单了。
我的代码的分解因子部分写丑了,但因为AC了,就懒地该成sqrt(N)的形式,大家不要学我qwq。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define maxn 500005 using namespace std; inline void read(int &x) { x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } int gcd(int a,int b) { if(a==0) return b; if(b==0) return a; return gcd(b,a%b); } struct node{ int nex,to; }edge[maxn]; int head[maxn],tot; int N,a[maxn]; inline void insert(int from,int to) { edge[++tot].nex=head[from]; edge[tot].to=to; head[from]=tot; } int dp_nroot[maxn],dp_all[maxn],dp_root[maxn],ans[maxn]; int p[maxn],id,num[maxn]; void init() { int n=a[1]/2; for(int i=2;i<=n;i++) if(a[1]%i==0) p[++id]=i; p[++id]=a[1]; } int dept[maxn]; void dfs(int x,int u) { dept[x]=dept[u]+1; if(x!=1) dp_nroot[x]=gcd(dp_nroot[u],a[x]); dp_all[x]=gcd(dp_all[u],a[x]); for(int i=1;i<=id;i++) if(a[x]%p[i]==0) num[i]++; /*cout<<"NOTE :"<<x<<endl; for(int i=1;i<=id;i++) cout<<num[i]<<" "; cout<<endl;*/ for(int i=id;i>0;i--) if(num[i]>=dept[x]-1) { dp_root[x]=p[i]; //cout<<"ROOT NTOE: "<<x<<" "<<p[i]<<endl; break; } ans[x]=max(dp_root[x],max(dp_nroot[x],dp_all[x])); for(int i=head[x];i;i=edge[i].nex) if(edge[i].to^u) dfs(edge[i].to,x); for(int i=1;i<=id;i++) if(a[x]%p[i]==0) num[i]--; } int main() { read(N); int u,v; for(int i=1;i<=N;i++) read(a[i]); for(int i=1;i<N;i++) { read(u); read(v); insert(u,v); insert(v,u); } init(); //for(int i=1;i<=id;i++) // cout<<p[i]<<" "; //cout<<endl; dfs(1,1); /*for(int i=1;i<=N;i++) cout<<dp_all[i]<<" "<<dp_nroot[i]<<" "<<dp_root[i]<<endl;*/ for(int i=1;i<=N;i++) printf("%d ",ans[i]); }