计蒜客 青云的机房组网方案

来源:互联网 发布:行测怎么提高常识 知乎 编辑:程序博客网 时间:2024/04/30 03:46

n(10w)个结点的树。边权为1,点权ai[1,10w]。求点权互质的点之间的距离之和。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define rep(x,st,en) for(int x=st;x<=en;x++)#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int M=100005;const int Num=100000;typedef long long ll;int nxt[M][18],bin[20];int dep[M];struct Edge{    int to,nxt;}edge[M<<2];//虚树中的边可以利用深度O(1)获得 int last[M];int head[M];int prv,allc;int mul[M];int id[M],n;ll ans,val;void ins(int u,int v){    edge[++allc]=(Edge){v,last[u]};    last[u]=allc;}void ins_(int u,int v){    edge[++allc]=(Edge){v,head[u]};    head[u]=allc;}bool cmp(int x,int y){    return id[x]<id[y];}int a[M+5];int tot,top,dfs_clock;int lca(int u,int v){    if(dep[u]<dep[v])swap(u,v);    int d=dep[u]-dep[v];    for(int i=0;i<18;i++)        if(bin[i]&d)            u=nxt[u][i];    if(u==v)return u;    for(int i=17;i>=0;i--)        if(nxt[u][i]!=nxt[v][i]){            u=nxt[u][i];            v=nxt[v][i];        }    return nxt[u][0];}int stk[M];int sz[M];void dfs1(int x,int f){    for(int i=last[x];i;i=edge[i].nxt){        int y=edge[i].to;        if(y!=f){            dfs1(y,x);            sz[x]+=sz[y];        }    }    if(f)val+=1ll*abs(dep[x]-dep[f])*sz[x]*(tot-sz[x]);}void clear(int x,int f){    for(int i=last[x];i;i=edge[i].nxt){        int y=edge[i].to;        if(y!=f)clear(y,x);    }    last[x]=sz[x]=0;}void solve(int K){    tot=top=0;    for(int i=K;i<=Num;i+=K)        for(int j=head[i];j;j=edge[j].nxt)            a[tot++]=edge[j].to;    if(tot<=1)return;    val=0;    allc=prv;    sort(a,a+tot,cmp);    for(int i=0;i<tot;i++)sz[a[i]]=1;    for(int i=0;i<tot;i++){        int f=0,s=a[i];        while(top>0){            f=lca(stk[top],s);            if(top>1&&dep[f]<dep[stk[top-1]]){                ins(stk[top],stk[top-1]);                ins(stk[top-1],stk[top]);                top--;            }            else if(dep[f]<dep[stk[top]]){                ins(stk[top],f);                ins(f,stk[top]);                top--;                break;            }            else break;        }        if(stk[top]!=f)stk[++top]=f;        stk[++top]=s;    }    while(top>1){        ins(stk[top],stk[top-1]);        ins(stk[top-1],stk[top]);        top--;    }    dfs1(a[0],0);    ans+=val*mul[K];    clear(a[0],0);//  printf("%I64d\n",val);}void dfs(int x,int f){    id[x]=++dfs_clock;    nxt[x][0]=f;    dep[x]=dep[f]+1;    for(int i=0;nxt[x][i];i++)        nxt[x][i+1]=nxt[nxt[x][i]][i];    for(int i=last[x];i;i=edge[i].nxt){        int y=edge[i].to;        if(y!=f)dfs(y,x);    }}char mark[M];int prm[M];void pre(){    int cnt=0;    mul[1]=1;    for(int i=2;i<=Num;i++){        if(!mark[i]){            prm[cnt++]=i;            mul[i]=-1;        }        for(int j=0;j<cnt&&i*prm[j]<=Num;j++){            mark[i*prm[j]]=true;            if(i%prm[j]==0){                mul[i*prm[j]]=0;                break;            }            else mul[i*prm[j]]=-mul[i];        }    }}int main(){    scanf("%d",&n);    pre();    for(int i=0;i<20;i++)bin[i]=1<<i;    for(int v,i=1;i<=n;i++){        scanf("%d",&v);        ins_(v,i);    }    prv=allc;    for(int u,v,i=1;i<n;i++){        scanf("%d%d",&u,&v);        ins(u,v);ins(v,u);    }    //这里的边得到dfs序和深度以后就用不到了     dfs_clock=0;    dfs(1,0);    ans=0;    for(int i=1;i<=n;i++)        last[i]=0;    for(int i=1;i<=Num;i++)        if(mul[i])solve(i);    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击