1. 程式人生 > >【洛谷P1351】聯合權值

【洛谷P1351】聯合權值

連結

這個題讓我們求得是最大聯合權值聯合權值之和

先來討論較簡單的,聯合權值之和。

當需要求兩個點之間的某些關係時,往往可以將其轉化成一個點的問題。

比如這個題,就可以通過列舉中間點,通過一些式子算出答案(如下圖)

指出的那一個點,以它為中點的答案之和就是它周圍一圈的點所有組合的答案之和,這一點很好想到。

列舉的話是不太好的,如果是一個200000的菊花圖,就完美的TLE了。

所以很明顯可以O(1)算出來。

一個點的答案,就是(與它相關點的和的平方-平方和)/2

模擬一下的話:

(a+b+c)^{2}=a^{2}+b^{2}+c^{2}+2ab+2ac+2bc;

ans=[(a+b+c)^{2}-(a^{2}+b^{2}+c^{2})]/2

然後?然後就完了啊。

有了這個思路以後,最大值和次大值順帶搞一搞就好了。

要注意有兩種情況:

1.當前權值大於這個點範圍內的最大值:m2=m1,m1=w;

2.當前權值大於次大值小於最大值:m2=w;

其他的隨緣就好了。

(我的程式碼好樸素啊)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define maxn 200005
#define mod 10007
using namespace std;
int n,x,y;
int sqr[maxn],sum[maxn],w[maxn],head[maxn];
int max1[maxn],max2[maxn];
struct node{
    int y,nxt;
}e[maxn*2];
int tot=0;
inline void ad(int x,int y){
    ++tot;
    e[tot].y=y;e[tot].nxt=head[x];head[x]=tot;
}
inline void dfs(int u,int fa)
{
    max1[u]=w[fa];
    int y;
    for(int i=head[u];i;i=e[i].nxt){
        y=e[i].y;
        if(y!=fa){
            if(w[y]>=max1[u]){
                max2[u]=max1[u];
                max1[u]=w[y];
            }
            else if(w[y]<max1[u]&&w[y]>max2[u])max2[u]=w[y];
        }
        sqr[u]=(sqr[u]+(w[y]*w[y])%mod)%mod;
        sum[u]=(sum[u]+w[y])%mod;
        if(y!=fa)dfs(y,u);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;++i){
        scanf("%d%d",&x,&y);
        ad(x,y);ad(y,x);
    }
    for(int i=1;i<=n;++i)
        scanf("%d",&w[i]);
    dfs(1,0);
    int ans=0,ans2=0;
    for(int i=1;i<=n;++i)
        ans=(ans+(sum[i]*sum[i]-sqr[i])%mod)%mod,
        ans2=max(ans2,max1[i]*max2[i]);
    printf("%d %d",ans2,ans);
}