NOIP2014Day1T2 联合权值

题目分析:

题目的第一句话告诉你这个图是一个树。

我们可以想到,对于节点u,每个与它相连的节点v,v的集合两两不重复的w的乘积就是题目所求。注意到题目要求为有序点对,也就是说(u,v)和(v,u)要分别计入答案。但是我们只要计算其中的一个,最后将答案乘2即可。

首先可以想到:枚举树上的所有点u,枚举u的所有边e1,枚举e1之后的每一个边e2,e1和e2的入点的w之积为一个答案。将它们累加如SUM,并与MAX比较。最后SUM=SUM*2 。

优化:

当我们枚举u的所有出边,假设这些边的入点为v1,v2,v3,v4,则以u为中继点的联合权值之和为:

S=v1v2+v1v3+v1v4+v2v3+v2v4+v3v4

利用分配率合并:

S=v2v1+v3(v1+v2)+v4(v1+v2+v3)

因此,枚举u的所有出边e1时,设s代表已经枚举的e1的入点的w的和,就可以省去枚举e2的步骤。

如是优化,时间复杂度为O(N+M)

代码细节:

也没什么细节。请参考代码部分。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 //variable//
 8 int last[200100],prel[400100],dest[400100],tot=1;
 9 int n,w[200100],maxx=-1e9,ans=0,mod=10007;
10 
11 //function prototype//
12 void addline(int,int);
13 void dfs(int,int);
14 
15 //solve//noip2014 day1 t2
16 int main(){
17     scanf("%d",&n);
18     int u,v;
19     for (int i=1;i<n;++i){
20         scanf("%d%d",&u,&v);
21         addline(u,v);
22         addline(v,u);
23     }
24     for (int i=1;i<=n;++i){
25         scanf("%d",w+i);
26     }
27     dfs(1,0);
28     printf("%d %d\n",maxx,(ans*2)%mod);
29 }
30 
31 void addline(int u,int v){
32     dest[++tot]=v;
33     prel[tot]=last[u];
34     last[u]=tot;
35 }
36 
37 void dfs(int x,int fa){
38     int sum=w[fa],MAX=w[fa];
39     for (int k=last[x];k;k=prel[k]){
40         if (dest[k]==fa) continue;
41         dfs(dest[k],x);
42         ans=(ans+sum*w[dest[k]])%mod;
43         sum=(sum+w[dest[k]])%mod;
44         maxx=max(maxx,MAX*w[dest[k]]);
45         MAX=max(MAX,w[dest[k]]);
46     }
47 }
View Code

 

转载于:https://www.cnblogs.com/ZXTLFDeAR/p/4797632.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值