【NOIP2014day1】聯合權值
阿新 • • 發佈:2021-01-19
題目
題解
首先這是棵樹,那麼任意兩點間就只有一條路徑。要想值為2,那麼就需要兩個點連到同一個點,即與同一個點直接相連
那麼我們就可以列舉中間的點,然後遍歷它所有與其相連的點。
另外總和權值可以這麼算:
假如有兩個點: 2 a b = ( a + b ) 2 − ( a 2 + b 2 ) 2ab=(a+b)^2-(a^2+b^2) 2ab=(a+b)2−(a2+b2)
假如有三個點:
2
a
b
+
2
a
c
+
2
b
c
=
(
a
+
b
+
c
)
2
−
(
a
2
+
b
2
+
c
2
)
2ab+2ac+2bc=(a+b+c)^2-(a^2+b^2+c^2)
2ab+2 ac+2bc=(a+b+c)2−(a2+b2+c2)
… \dots …
n n n個點: a n s = ( ∑ w i ) 2 − ∑ w i 2 ans=(\sum w_i)^2-\sum w_i^2 ans=(∑wi)2−∑wi2
最大權值可以求出最大點權和次大點權,然後與答案比較一下就可以了
PS:只有總和要sro%orz,最大值不用sro%orz
Code
#include<cstdio>
#include<algorithm>
#define p 10007
#define ll long long
using namespace std;
struct node
{
int to,head,next;
}map[400005];
int n,x,y,tot;
ll mx,mx1,mx2,ans,sum,a[200005];
void add(int x,int y)
{
map[++tot].to=y;
map[tot].next=map[x].head;
map[x].head=tot;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
add(x,y);
add (y,x);
}
for (int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for (int i=1;i<=n;++i)
{
mx1=0;mx2=0;
sum=0;
for (int j=map[i].head;j;j=map[j].next)
{
sum+=a[map[j].to];
ans-=a[map[j].to]*a[map[j].to];
if (a[map[j].to]>=mx1) mx2=mx1,mx1=a[map[j].to];
else if (a[map[j].to]>mx2) mx2=a[map[j].to];
}
ans+=sum*sum;
mx=max(mx,mx1*mx2);
}
printf("%lld %lld\n",mx,ans%p);
return 0;
}