[FZYZOJ 2044] [NOIP 2014 D1T2] 联合权值
[NOIP2014_D1_T2]联合权值
时间限制:1000MS
内存限制:131072KB
Description
无向连通图 G 有 n 个点,n−1 条边。点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi,每条边的长度均为 1。图上两点 (u,v) 的距离定义为 u 点到 v 点的最短距离。对于图 G 上的点对 (u,v),若它们的距离为 2,则它们之间会产生Wv×Wu 的联合权值。
请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?
Input Format
第一行包含 1 个整数 n。
接下来 n−1 行,每行包含 2 个用空格隔开的正整数 u,v,表示编号为 u 和编号为 v 的点之间有边相连。
最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图 G 上编号为 i 的点的权值为 Wi。
Output Format
输出共 1 行,包含 2 个整数,之间用一个空格隔开,依次为图 G 上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007取余。
Sample Input
5 1 2 2 3 3 4 4 5 1 5 2 3 10
Sample Output
20 74
Hint
距离为 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≤200000,0<Wi≤10000。
保证一定存在可产生联合权值的有序点对。
【题解】
用边链表存储,枚举每个点,找到这个点连接的边,从他出发的两条边的终点间的距离即为2。
感谢 miskoo,只需要记录所有的和,然后加w*(t-w)即可。
↑这是一个高大上的方法↑
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,cnt=0; 4 struct edge { 5 int to,next; 6 }e[400010]; 7 int w[200010]; 8 int head[200010]; 9 int ans=0,maxx=-1; 10 inline int read() { 11 int x=0,f=1;char ch; 12 ch=getchar(); 13 while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();} 14 while(ch<='9'&&ch>='0') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 void addedge(int u,int v) { 18 e[++cnt].to=v; 19 e[cnt].next=head[u]; 20 head[u]=cnt; 21 } 22 int main() { 23 n=read(); 24 for(int i=1;i<n;++i) { 25 int from,to; 26 from=read();to=read(); 27 addedge(from,to); 28 addedge(to,from); 29 } 30 for (int i=1;i<=n;++i) w[i]=read(); 31 for (int i=1;i<n;++i) { 32 int max1=-1,max2=-1,t=0,wx; 33 for (int j=head[i];j;j=e[j].next) { 34 wx=w[e[j].to]; 35 t=t+wx,t%=10007; 36 if(wx>max1) { 37 max2=max1; 38 max1=wx; 39 } 40 else if(wx>max2) { 41 max2=wx; 42 } 43 } 44 max1*=max2; 45 if(max1>maxx) maxx=max1; 46 for (int j=head[i];j;j=e[j].next) { 47 wx=w[e[j].to]; 48 ans+=wx*(t-wx),ans%=10007; 49 } 50 } 51 ans=(ans+10007)%10007; 52 printf("%d %d\n",maxx,ans); 53 return 0; 54 }
这篇文章由TonyFang发布。
所有解释权归TonyFang所有。
Mailto: tony-fang@map-le.net