【mt noip模拟题】最大公倍树

来源:互联网 发布:跳跃网络上天了? 编辑:程序博客网 时间:2024/04/30 04:49
求一个无向带权连通图的所有极小连通子图的所有边权的最大公约数的最小公倍

数。

更清楚的说就是,令带权连通图的一个极小连通子图的权值为所有
边权的最大公约数,带权连通图的权值为所有极小连通子图的最小公倍数。答案可能很大,
请对 2^31-1 取模。 

就如mt的xor题是分位考虑一般,此题要分质因子考虑,对于一个质因子最后出现在答案里是最大瓶颈树上的最大瓶颈边,最后求出lcm即可。

但是,裸枚会超的,可知超过sqrt(max)的质因子只会出现一次,因此判联通即可。

质因子预处理会快很多,但是我还是超了一个点,我也木办法了。

#include <cstdio>#include <cstdlib>#include <cstring>struct line {int l,r,w[200];}a[200000];const long long mo=0x7FFFFFFF,e=32768;int l[200000],r[200000],w[200000],n,m,b[200000],v[200000],t,ws[200000],sa[200000],h,sum[200000],check[e+e],prim[e+e],tot;long long ans,st[200000],ts[200000];inline int find(int x) {if (x!=b[x]) b[x]=find(b[x]);return b[x];}inline void make(int i){  int ww,j,k;  a[i].l=l[i],a[i].r=r[i];  ww=w[i];  for (k=1;ww!=1;k++) {    j=prim[k];    if (j>190) j=ww;    if (ww%j==0)       if (j>=200) {       if (!sum[j]) ts[++h]=j;       sum[j]++;      }    for (;ww%j==0;) {      if (!v[j]) {        if (j<200) v[j]=++t,st[t]=j;      }      a[i].w[v[j]]++;      ww/=j;    }  }}void origin(){  int i,j;  for (i=2;i<=e;i++) {    if (!check[i]) prim[++tot]=i;    for (j=1;j<=tot;j++) {      if (i*prim[j]>e) break;      check[i*prim[j]]=1;      if (i%prim[j]==0) break;    }  }}void init(){  int i,j,p,ll,rr;  line x;  scanf("%d%d\n",&n,&m);  origin();  for (i=1;i<=m;i++) {    scanf("%d%d%d\n",&l[i],&r[i],&w[i]);    make(i);  }  ans=1;  for (i=1;i<=t;i++) {    for (j=1;j<=e;j++) ws[j]=0;    for (j=1;j<=m;j++) ws[a[j].w[i]]++;    for (j=1;j<=e;j++) ws[j]+=ws[j-1];    for (j=m;j>=1;j--) sa[ws[a[j].w[i]]--]=j;    for (j=1;j<=n;j++) b[j]=j;    for (j=m,p=0;j>=1;j--) if (sa[j]!=0) {      x=a[sa[j]];      ll=find(x.l),rr=find(x.r);      if (ll!=rr) {        ++p,b[ll]=rr;        if (n-1==p) break;      }    }    if (n-1==p) for (j=1;j<=x.w[i];j++) ans=(ans*st[i]&mo);  }  for (i=1;i<=h;i++) if (sum[ts[i]]>=n-1) {    for (j=1;j<=n;j++) b[j]=j;    for (j=1,p=0;j<=m;j++) if (w[j]%ts[i]==0) {      ll=find(l[j]),rr=find(r[j]);      if (ll!=rr) {        ++p,b[ll]=rr;        if (n-1==p) break;              }    }    if (n-1==p) ans=(ans*ts[i]&mo);  }  printf("%I64d\n",ans);}int main(){  freopen("input.txt","r",stdin);  freopen("output.txt","w",stdout);    init();  return 0;}