• NOIp2014 T2联合权值


    背景

    NOIP2014提高组第二题

    描述

    无向连通图G有n个点,n-1条边。点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1。图上两点(u, v)的距离定义为u点到v点的最短距离。对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值。

    请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

    输入格式

    输入文件名为link.in。

    第一行包含1个整数n。

    接下来n-1行,每行包含2个用空格隔开的正整数u、v,表示编号为u和编号为v的点之间有边相连。

    最后1行,包含n个正整数,每两个正整数之间用一个空格隔开,其中第i个整数表示图G上编号为i的点的权值为Wi。

    输入样例:

    5

    1 2

    2 3

    3 4

    4 5

    1 5 2 3 10

    输出格式

    输出文件名为link.out。

    输出共1行,包含2个整数,之间用一个空格隔开,依次为图G上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007取余。

    输出样例:

    20 74

    备注

    对于30%的数据,1<n≤100;

    对于60%的数据,1<n≤2000;

    对于100%的数据,1<n≤200,000,0<Wi ≤10,000。

    首先观察数据发现60%的数据是可以直接过的。

    进一步,在模拟数据的时候不难发现可以用树形dp做:

    1、提出一个点来作为根

    2、记录每个点的父亲以及孩子

    3、对于有两个及以上的孩子,任意两个孩子到该点的距离为2,对此进行(a+b)^2-(a^2+b^2)的运算

    4、对于有父亲的呢节点,直接计算sum_son与value[father]的乘积的2倍。

    一年不写的code:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MOD = 10007;
    const int N = 200010;
    #define For(i,n) for(int i=1;i<=n;i++)
    #define Rep(i,l,r) for(int i=l;i<=r;i++)
    
    struct Edge{
        int s,t,next;
    }E[N*2];
    
    int ansmax,First,Second,es,n,cnt[N],value[N],ans,sonsqr[N],son[N],father[N],head[N];
    bool vis[N];
    
    void makelist(int s,int t){
        E[es].s=s;E[es].t=t;
        E[es].next=head[s];head[s]=es++;
    }
    
    int Dfs(int s,int fa){
        int p=head[s];vis[s]=true;
        int First=value[fa],Second=0;
        while(p!=-1){
            int t=E[p].t;
            if(!vis[t]){
                sonsqr[s]=(sonsqr[s]+(value[t]*value[t])%MOD)%MOD;
                son[s]=(son[s]+value[t])%MOD;cnt[s]++;
                if(value[t]>First) Second=First,First=value[t];
                else  if(value[t]>Second) Second=value[t];
                Dfs(t,s);
            }
            p=E[p].next;
        }
        father[s]=fa;
        ansmax=max(ansmax,First*Second);
    }
    
    int main(){
        freopen("link.in","r",stdin);
        freopen("link.out","w",stdout);
        memset(head,-1,sizeof(head));
        scanf("%d",&n);int x,y;
        For(i,n-1){
            scanf("%d%d",&x,&y);
            makelist(x,y);makelist(y,x);
        }
        For(i,n) {
            scanf("%d",&value[i]);
            value[i]%=MOD;
        }
        Dfs(1,0);
        For(s,n){
            if(cnt[s]>1){
                int ans1=son[s]%MOD,ans1sqr=sonsqr[s]%MOD;
                ans=(ans+(ans1*ans1-ans1sqr)%MOD)%MOD;
            }
            if(father[s]!=0){
                ans=(ans+son[s]*value[father[s]]*2)%MOD;
            }
        }
        printf("%d %d
    ",ansmax,(ans+MOD)%MOD);
        return 0;
    }
    Dfs版
  • 相关阅读:
    解读MSP430F169的头文件们
    解决编辑安装falkon中碰到缺少ecm问题
    vim基础普及
    本科2020专业目录
    cp 文件复制命令
    mkdir rmdir
    whereis ,which 文件查找
    gitlab软件的安装与使用
    如何节省数据库的成本
    innodb_undo_tablespaces参数引发的启动报错
  • 原文地址:https://www.cnblogs.com/zjdx1998/p/4844812.html
Copyright © 2020-2023  润新知