2012-A3-0006

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

大意:删去一颗无根树的一个顶点,使分裂的各部分的点权和的乘积最大,

比较简单的树形DP,随机选取一个作为根DFS遍历树,pt[u]表示以u为根的子数的点权和。

那么删去它的结果就是 (sum(pt[i],i =1..n) - pt[u]) * product(pt[v],v为dfs时u的子节点)

需要高精度,但是如果乘积的对数,有明显大小关系,就可以直接判断是否为答案,否则还是计算出结果比较比较保险。



{{{
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
typedef unsigned num;
typedef unsigned long long ull;
typedef long double real;

num ptr[102400],eg[204800],nx[204800],pt[102400],tot;
real ans;

struct high{
    num bit[32],L;
    static const num Dec = 1000000000u;
    void init(num x){
        memset(bit,0,sizeof(bit));
        bit[0]=x;L=1;
    }
    void operator *=(num rhs){
        ull x = 0;
        for(num i=0;i<L;++i){
            x+= bit[i]*(ull)rhs;
            bit[i] = x% Dec;
            x /= Dec;
        }
        for(;x;x/=Dec)
            bit[L++]=x%Dec;
    }
    bool operator >(const high & rhs){
        if(L != rhs.L)
            return L>rhs.L;
        else for(num j=L;j--;)
            if( bit[j]!=rhs.bit[j])
                return bit[j]>rhs.bit[j];
        return false;
    }
    void out(){
        printf("%u",bit[L-1]);
        for(num i=L-1;i--;printf("%09u",bit[i]));
    }
} tmpx,ansx;
void dfs(num u,num fr){
    real tmp = 0;
    for(num p= ptr[u],v;p;p= nx[p])
    if((v=eg[p])!=fr){
        dfs(v,u);
        pt[u]+=pt[v];
        tmp += log(pt[v]);
    }
    tmp += log(tot-pt[u]);
    if(__builtin_expect((tmp+1e-20>ans),0)){
        tmpx.init(tot -pt[u]);
        for(num p= ptr[u],v;p;p= nx[p])
        if((v=eg[p])!=fr)
            tmpx*=pt[v];
        if(tmpx>ansx)
            ansx =tmpx;
    }
}
int main(){
    srand(time(NULL));
    for(num n,rt,m;1==scanf("%u",&n);puts("")){
        for(num i=tot=0;i<n;++i){
            scanf("%u",pt+i);
            tot += pt[i];
        }
        m=0;
        memset(ptr,0,n<<2);
        for(num i=n,a,b;--i;){
            scanf("%u%u",&a,&b);
            --a;--b;
            eg[++m]=b;nx[m]=ptr[a];ptr[a]=m;
            eg[++m]=a;nx[m]=ptr[b];ptr[b]=m;
        }
        rt=rand()%n;
        ans =0;ansx.init(0);
        dfs(rt,~0);
        ansx.out();
    }
}
}}}

大意:删去一颗无根树的一个顶点,使分裂的各部分的点权和的乘积最大,

比较简单的树形DP,随机选取一个作为根DFS遍历树,pt[u]表示以u为根的子数的点权和。

那么删去它的结果就是 (sum(pt[i],i =1..n) - pt[u]) * product(pt[v],v为dfs时u的子节点)

需要高精度,但是如果乘积的对数,有明显大小关系,就可以直接判断是否为答案,否则还是计算出结果比较比较保险。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
typedef unsigned num;
typedef unsigned long long ull;
typedef long double real;
num ptr[102400],eg[204800],nx[204800],pt[102400],tot;
real ans;
struct high{
    num bit[32],L;
    static const num Dec = 1000000000u;
    void init(num x){
        memset(bit,0,sizeof(bit));
        bit[0]=x;L=1;
    }
    void operator *=(num rhs){
        ull x = 0;
        for(num i=0;i<L;++i){
            x+= bit[i]*(ull)rhs;
            bit[i] = x% Dec;
            x /= Dec;
        }
        for(;x;x/=Dec)
            bit[L++]=x%Dec;
    }
    bool operator >(const high & rhs){
        if(L != rhs.L)
            return L>rhs.L;
        else for(num j=L;j--;)
            if( bit[j]!=rhs.bit[j])
                return bit[j]>rhs.bit[j];
        return false;
    }
    void out(){
        printf("%u",bit[L-1]);
        for(num i=L-1;i--;printf("%09u",bit[i]));
    }
} tmpx,ansx;
void dfs(num u,num fr){
    real tmp = 0;
    for(num p= ptr[u],v;p;p= nx[p])
    if((v=eg[p])!=fr){
        dfs(v,u);
        pt[u]+=pt[v];
        tmp += log(pt[v]);
    }
    tmp += log(tot-pt[u]);
    if(__builtin_expect((tmp+1e-20>ans),0)){
        tmpx.init(tot -pt[u]);
        for(num p= ptr[u],v;p;p= nx[p])
        if((v=eg[p])!=fr)
            tmpx*=pt[v];
        if(tmpx>ansx)
            ansx =tmpx;
    }
}
int main(){
    srand(time(NULL));
    for(num n,rt,m;1==scanf("%u",&n);puts("")){
        for(num i=tot=0;i<n;++i){
            scanf("%u",pt+i);
            tot += pt[i];
        }
        m=0;
        memset(ptr,0,n<<2);
        for(num i=n,a,b;--i;){
            scanf("%u%u",&a,&b);
            --a;--b;
            eg[++m]=b;nx[m]=ptr[a];ptr[a]=m;
            eg[++m]=a;nx[m]=ptr[b];ptr[b]=m;
        }
        rt=rand()%n;
        ans =0;ansx.init(0);
        dfs(rt,~0);
        ansx.out();
    }
}