Noip 2014 提高组 联合权值

xiaoxiao2021-02-28  107

题目

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

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

分析

70分:利用邻接表,强行找相隔的一个点。

100分:观察一下,题目给的是一棵树。距离相差为1可以转化为一个父亲的两个儿子。

假如一个根有三个儿子a,b,c。那么他们的权值和=a*b+b*a+a*c+c*a+b*c+c*b=(a+b+c)^2-a^2-b^2-c^2。

只要统计出以每个点为根儿子权值的和,进行一下处理就可以过了。

代码

#include<cstdio> using namespace std; #define inf 2147483646 #define to e[i].v #define ll long long #define M 10007 #define N 200010 struct node{ll v,next;}e[N*2]; ll head[N*2],vis[N],a[N],size[N]; ll id,n,mx,sum; ll read() { ll x=0,f=1; char ch=getchar(); for (;ch>'9' || ch<'0';ch=getchar()) if (ch=='-') f=-1; for (;ch>='0' && ch<='9';ch=getchar()) x=x*10+ch-'0'; return x*f; } void swap(ll &a,ll &b) {ll t=a; a=b; b=t;} ll max(ll a,ll b) {return a>b? a:b;} ll min(ll a,ll b) {return a>b? b:a;} void add(ll u,ll v) {e[id].v=v; e[id].next=head[u]; head[u]=id++;} int main() { n=read(); id=1; mx=0; for (ll i=1;i<n;i++) { ll u=read(),v=read(); add(u,v); add(v,u); } for (ll i=1;i<=n;i++) a[i]=read(); for (ll u=1;u<=n;u++) { ll max1=0,max2=0; for (ll i=head[u];i;i=e[i].next) { size[u]=(size[u]+a[to])%M; vis[to]++; if (a[to]>max1) {max2=max(max1,max2); max1=a[to]; continue;} max2=max(a[to],max2); } mx=max(mx,max1*max2); } sum=0; for (ll i=1;i<=n;i++) { sum=(sum+size[i]*size[i]%M)%M; sum=(sum-((a[i]*a[i])%M)*vis[i]%M+M)%M; } printf("%lld %lld",mx,sum); return 0; }

转载请注明原文地址: https://www.6miu.com/read-51320.html

最新回复(0)