zoukankan      html  css  js  c++  java
  • [NOIP2014]联合权值

    NOIp2014提高组

    【题目描述】

    无向连通图G 有n 个点,n - 1 条边。点从1 到n 依次编号,编号为 i 的点的权值为W i   ,每条边的长度均为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 的点的权值为W i 。

    输出格式:

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

    【输入输出样例】

    输入样例#1:

    5  
    1 2  
    2 3
    3 4  
    4 5  
    1 5 2 3 10 

    输出样例#1:

    20 74

    【说明】


         本例输入的图如上所示,距离为2 的有序点对有( 1,3) 、( 2,4) 、( 3,1) 、( 3,5) 、( 4,2) 、( 5,3) 。 
    其联合权值分别为2 、15、2 、20、15、20。其中最大的是20,总和为74。 

    【数据说明】

     对于30% 的数据,1 < n≤ 100 ; 
    对于60% 的数据,1 < n≤ 2000; 
    对于100%的数据,1 < n≤ 200 , 000 ,0 < wi≤ 10, 000 。

    【思路】

     60%:用暴力搜索可以将解决60%的数据,如果i和j相连,j和k相连,i和k不相连,那么可以认为i和k可以构成联合最大权值,用一个O(N^3)的循环即可。

     100%:

      这个题AC的思路很多,可以跑树,用LCA处理两个兄弟之间的关系,也可以跑图,想要,存储一定要用前向星。(不会问度娘)。我能够AC还要感谢@yangs_s,如果不是他的博客http://blog.csdn.net/yangs_s/article/details/47359967,这个题我也做不出AC来的,我在这里把他的思路说一下吧。

      有两个关键点。

      首先输出分为两部分,可以把题目分成两部分来看,对一个点来说,最大的乘积自然就是和它相邻的两个权值最大的节点的权值的乘积, 读入后顺手处理一下就能出来。

      第二个关键点就是加法结合律。

      没错,加法结合律!

      我看到神犇的博客后伏案长叹,这是小学三年级的内容,我就这样还给老师了。

      我们假设和o点相邻的点有a,b,c,d,e,f,g七个,假设他们的权值就是a,b,c,d,e,f,g。某二逼青年的计算过程是这样的:sum:=a·b+a·c+a·d…….+a….+e*g….,但其实我们这样处理,我们先用加法运算法则,发现sum其实就是每个点的权值乘以可以联合(距离为2)的节点的所有权值之和,所以说,我们在读入数据的时候,可以预先处理一下,把每个节点周围相邻节点的权值之和给加起来,就以上述为例,在处理时,把a,b,c….g的权值加起来为s[o]{o点相邻点的权值之和},然后在计算时,就可以用sum:=a·(s[o]-a)+b·(s[o]-b)…..很自然的结果就出来了!

      算法的时间复杂度应该是O(kn),k应该是一个很小很小远小于N的常数,应该和LCA的差不多了吧。 

    const ma=10007;
    const mx=200000;
    
    type ss=record
        u,v:longint;
        end;
    
    var s:array[1..mx] of int64;//s[i]表示和结点i所有相连的点的权值之和
        e:array[1..mx] of ss;//存的是边
        w,max1,max2:array[1..mx]of longint;
    {w[i]表示第i个点的权值
     max1[i]表示和i相连得结点中权值最大的结点
     max2[i]表示和i相连得结点中权值最小的结点
     }
        n,i,j,ans1,ans2:longint;
    
    procedure box;
    var i,j:longint;
    begin
        fillchar(s,sizeof(s),0);
        fillchar(e,sizeof(e),0);
        fillchar(w,sizeof(w),0);
        fillchar(max1,sizeof(max1),0);
        fillchar(max2,sizeof(max2),0);
        ans1:=0;
        ans2:=0;
    end;
    //变量初始化
    
    procedure work(x:longint;var a,b:longint);
    //x的值是不会被改变的,a和b是可以被改变的
    begin
    //首先已经得出值的数组是合法的,再次更改过后也一定是合法的
        if x>a then
            begin
                b:=a;
                a:=x;
            end
        else
            if x>b then b:=x;
    end;
    //用来比较大小的过程,必须用全局变量
    
    procedure change;
    var i,u,v:longint;
    begin
        for i:=1 to n-1 do
            begin
                u:=e[i].u;
                v:=e[i].v;
                inc(s[u],w[v]);
                inc(s[v],w[u]);
                work(w[v],max1[u],max2[u]);
                work(w[u],max1[v],max2[v]);
                //不断更新结点周围的最大值和次大值
            end;
    end;
    //预处理程序
    
    procedure main1;
    var i:longint;
    begin
        for i:=1 to n do
            if max1[i]*max2[i]>ans1 then
                ans1:=max1[i]*max2[i];
    end;
    //处理最大的联合权值
    
    procedure main2;
    var i,j,u,v:longint;
    begin
        for i:=1 to n-1 do
            begin
                u:=e[i].u;
                v:=e[i].v;
                ans2:=(ans2+((s[u]-w[v])*w[v]) mod ma) mod ma;
                ans2:=(ans2+((s[v]-w[u])*w[u]) mod ma) mod ma;
            end;
    end;
    //处理权值之和
    
    procedure init;
    var i,j:longint;
    begin
        readln(n);
        for i:=1 to n-1 do
            readln(e[i].u,e[i].v);
        for i:=1 to n do read(w[i]);
    end;
    
    procedure printf;
    begin
        writeln(ans1,' ',ans2);
    end;
    
    begin
        box;
        init;
        change;
        main1;
        main2;
        printf;
    end.
  • 相关阅读:
    java返回json数据日期为一串数字字符串 js 转义
    ==和equals以及hashcode
    【线程分析】
    【dubbo&zookeeper】
    线程安全实现方案
    IOC原理
    java锁
    java特殊运算符
    HashMap原理和TreeMap原理
    volatile与synchronized
  • 原文地址:https://www.cnblogs.com/yangqingli/p/4721774.html
Copyright © 2011-2022 走看看