[ ST表 並查集 樹的直徑 ] Codechef March Cook-Off 2018 Maximum Tree Path

先枚舉 gcd ,把所有邊找出來,按照權值小的端點排序,然後從大到小枚舉邊,並查集維護直徑就好了。
時間複雜度 O(nAi(logn+α))

#include<bits/stdc++.h>
using namespace std;
char nc() {
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
void Read(int& x) {
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
typedef long long ll;
const int N=200010;
const int M=18;
int k,n,m,x,y,z,T;
int cnt,cur,mx;
int a[N];
int u[N],v[N];
int f[N],A[N],B[N],lst[N];
int nx[N],t[N],w[N],h[N],num;
int pos[N],lg2[N];
ll dis[N];
ll Ans,Res,d[N],c[N],st[N][M],ed[N][M];
vector<int>g[10010];
void Add(int x,int y,int z) {
    t[++num]=y;w[num]=z;nx[num]=h[x];h[x]=num;
}
int Gcd(int x,int y) {
    return !y?x:Gcd(y,x%y);
}
void Update(int x,int y) {
    for(int i=1;i*i<=x;i++)
        if(!(x%i)) {
            g[i].push_back(y);
            if(i*i!=x) g[x/i].push_back(y);
        }
}
void Dfs(int x,int y) {
    c[++cnt]=d[x];pos[x]=cnt;
    for(int i=h[x];i;i=nx[i])
        if(t[i]!=y) {
            d[t[i]]=d[x]+w[i];
            Dfs(t[i],x);
            c[++cnt]=d[x];
        }
}
void init() {
    cnt=0;
    Dfs(1,0);
    for(int i=2;i<=cnt;i++) lg2[i]=lg2[i>>1]+1;
    for(int i=1;i<=cnt;i++) st[i][0]=ed[i][0]=c[i];
    for(int j=1;j<M;j++)
        for(int i=1;i<=cnt;i++) {
            int t=1<<j-1;
            if(i+(t<<1)-1<=cnt) st[i][j]=min(st[i][j-1],st[i+t][j-1]);
            if(i-(t<<1)>=0) ed[i][j]=min(ed[i][j-1],ed[i-t][j-1]); 
        }
}
ll Query(int l,int r) {
    l=pos[l];r=pos[r];
    if(l>r) swap(l,r);
    int k=lg2[r-l+1];
    return min(st[l][k],ed[r][k])<<1;
}
bool Cmp(int x,int y) {
    return a[u[x]]>a[u[y]];
}
int Find(int x) {
    return f[x]==x?x:f[x]=Find(f[x]);
}
void Un(int x,int y) {
    if(lst[x]!=cur) lst[x]=cur,f[x]=A[x]=B[x]=x,dis[x]=0;
    if(lst[y]!=cur) lst[y]=cur,f[y]=A[y]=B[y]=y,dis[y]=0;
    x=Find(x);y=Find(y);
    f[y]=x;
    int a1=A[x],b1=B[x];
    if(dis[y]>dis[x]) dis[x]=dis[y],a1=A[y],b1=B[y];

    ll t=d[A[x]]+d[A[y]]-Query(A[x],A[y]);
    if(t>dis[x]) dis[x]=t,a1=A[x],b1=A[y];

    t=d[A[x]]+d[B[y]]-Query(A[x],B[y]);
    if(t>dis[x]) dis[x]=t,a1=A[x],b1=B[y];

    t=d[B[x]]+d[A[y]]-Query(B[x],A[y]);
    if(t>dis[x]) dis[x]=t,a1=B[x],b1=A[y];

    t=d[B[x]]+d[B[y]]-Query(B[x],B[y]);
    if(t>dis[x]) dis[x]=t,a1=B[x],b1=B[y];

    A[x]=a1;B[x]=b1;
    Res=max(Res,dis[x]);
}
void Solve(int id) {
    sort(g[id].begin(),g[id].end(),Cmp);
    ++cur;Res=0;
    for(int i=0;i<g[id].size();i++) {
        int x=g[id][i];
        Un(u[x],v[x]);
        Ans=max(Ans,Res*id*a[u[x]]);
    }
}
int main() {
    Read(T);
    while(T--) {
        Read(n);
        mx=0;
        for(int i=1;i<=n;i++) Read(a[i]),h[i]=0,mx=max(mx,a[i]);
        for(int i=1;i<=mx;i++) g[i].clear();
        num=0;
        for(int i=1;i<n;i++) {
            Read(x),Read(y),Read(z),Add(x,y,z),Add(y,x,z),u[i]=x,v[i]=y;
            if(a[u[i]]>a[v[i]]) swap(u[i],v[i]);
            Update(Gcd(a[u[i]],a[v[i]]),i);
        }
        init();
        Ans=0;
        for(int i=1;i<=mx;i++) Solve(i);
        printf("%lld\n",Ans);
    }
    return 0;
}
發佈了288 篇原創文章 · 獲贊 104 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章