联合权值
题目描述
无向连通图G 有n 个点,n - 1 条边。点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 。图上两点( u , v ) 的距离定义为u 点到v 点的最短距离。对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu
×Wv 的联合权值。
请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?
×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 取余。
输入文件名为link .in。
第一行包含1 个整数n 。
接下来n - 1 行,每行包含 2 个用空格隔开的正整数u 、v ,表示编号为 u 和编号为v 的点之间有边相连。
最后1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图G 上编号为i 的点的权值为W i 。
输出格式:
输出文件名为link .out 。
输出共1 行,包含2 个整数,之间用一个空格隔开,依次为图G 上联合权值的最大值
和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007 取余。
输入样例:
5
1 2
2 3
3 4
4 5
1 5 2 3 10
输出样例:
20 74
说明
【数据说明】
对于30% 的数据,1 < n≤ 100 ;
对于60% 的数据,1 < n≤ 2000;
对于100%的数据,1 < n≤ 200 , 000 ,0 < wi≤ 10, 000 。
//都知道(a+b)^2=a^2+2*a*b+b^2; //那么2*a1a2+2*a1*a3+2*a1*a4...+2*a(n-1)*an=(a1+a2+a3+...+an)^2-a1^2-a2^2-a3^2-...-an^2; #include<cstdio> #include<vector> using namespace std; int n,x,y,sz[200002],i; bool f[200002]; int ansx=0,ans; vector<int> map[200002]; int main(){ scanf("%d",&n); for(i=1;i<=n;i++) map[i].push_back(0); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); map[x][0]++; map[x].push_back(y); map[y][0]++; map[y].push_back(x);//保存各点所连接的点; } for(i=1;i<=n;i++) scanf("%d",&sz[i]); for(i=1;i<=n;i++){ if(map[i][0]>1){ int max1=0,max2=0; int fh=0,hf=0,g=0; int j; for(j=1;j<=map[i][0];j++){//找到最大的值; if(sz[map[i][j]]>max1){ f[g]=0; g=j; max1=sz[map[i][j]]; f[j]=1; } hf=(hf+sz[map[i][j]])%10007; //与第i个点相连的点的权值累和; fh=(fh+sz[map[i][j]]*sz[map[i][j]])%10007;//与第i个点相连的点的权值的平方和 } for(j=1;j<=map[i][0];j++) if(sz[map[i][j]]>max2&&!f[j]) max2=sz[map[i][j]];//找第二大的值; f[g]=0; if(max1*max2>ansx) ansx=max1*max2; //储存最大值; while(hf<fh) hf+=10007; //取模后和的平方可能小于平方和,故+10007; hf*=hf; hf=(hf-fh)%10007; ans=(ans+hf)%10007; } } printf("%d %d ",ansx,ans); return 0; }