1. 程式人生 > >【bzoj 5200】Factor-Free Tree(分治+啟發式分裂)

【bzoj 5200】Factor-Free Tree(分治+啟發式分裂)

傳送門biu~
預處理每個點能作為樹根的區間,即預處理出每一個數左邊和右邊第一個與它不互質的數的位置。可以發現對於一棵子樹,以任一合法的點作為根都是一定成立的。用【bzoj 4059】Non-boring sequences的啟發式分裂思想進行遞迴驗證。時間複雜度O(nlogn)

#include<bits/stdc++.h>
#define N 1000050
using namespace std;
int n,Max,a[N],pre[10*N],f[10*N],fa[N],prime[10*N],Ls[N],Rs[N],tp;
bool b[10*N];
inline void
Get_Prime(){ for(int i=2;i<=Max;++i){ if(!b[i]) prime[++tp]=i,f[i]=i; for(int j=1;j<=tp && 1ll*i*prime[j]<=Max;++j){ b[i*prime[j]]=true; f[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; } } } bool solve(int l,int r,int f){ if
(l>r) return true; int x=l,y=r; while(x<=y){ if(Ls[x]<l && Rs[x]>r){ fa[x]=f; return solve(l,x-1,x) && solve(x+1,r,x); } if(Ls[y]<l && Rs[y]>r){ fa[y]=f; return solve(l,y-1,y) && solve(y+1
,r,y); } ++x,--y; } return false; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]),Max=max(Max,a[i]); Get_Prime(); for(int i=1;i<=n;++i){ int now=a[i],L=0; while(now^1){ int g=f[now]; L=max(L,pre[g]); pre[g]=i; while(now%g==0) now/=g; } Ls[i]=L; } for(int i=1;i<=Max;++i) pre[i]=n+1; for(int i=n;i>=1;--i){ int now=a[i],R=n+1; while(now^1){ int g=f[now]; R=min(R,pre[g]); pre[g]=i; while(now%g==0) now/=g; } Rs[i]=R; } if(solve(1,n,0)) for(int i=1;i<=n;++i) printf("%d ",fa[i]); else puts("impossible"); return 0; }