洛谷P1351 聯合權值(NOIp2014)
阿新 • • 發佈:2019-01-23
技巧題
題目意思很簡單,求兩個距離為2的點的點權。可以轉化為求一個點其中兩條出邊的點權。
剛開始寫DFS,然後華麗麗地T掉了。。。以為哪裡寫掛了,算了一下發現是的。。。於是重新想演算法
後來發現一個公式:,
它的拓展式也是成立的。(證明的話展開化簡即可)
於是我們只需要遍歷一遍就行了,算值的時候把這個東西代進去。求最大值就是求前二大值的積。
程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 200000
#define DALAO 10007
using namespace std;
typedef long long LL;
struct edge{
int next,to;
};
int n,k;
LL sum,ans;
int h[MAXN+5],w[MAXN+5];
edge ed[MAXN*2+5];
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int num=0; char ch=readc();
while (ch<'0'||ch>'9') ch=readc();
while (ch>='0'&&ch<='9') { num=num*10+ch-48; ch=readc(); }
return num;
}
void addedge(int x,int y){
ed[++k].next=h[x]; ed[k].to=y; h[x]=k;
}
void calc(int x){
LL s1=0,s2=0,t1=0,t2=0;
for (int i=h[x];i;i=ed[i].next){
int v=ed[i].to;
s1+=w[v]; s2+=w[v]*w[v];
if (t1<w[v]) t1=w[v];
else if (w[v]>t2) t2=w[v];
}
s1*=s1; ans=max(ans,t1*t2); sum=(((s1-s2)%DALAO+sum)%DALAO)%DALAO;
}
int main(){
n=_read();
for (int i=1;i<n;i++){
int u=_read(),v=_read();
addedge(u,v); addedge(v,u);
}
for (int i=1;i<=n;i++) w[i]=_read();
for (int i=1;i<=n;i++) calc(i);
printf("%lld %lld\n",ans,sum%DALAO);//其實並不需要long long
return 0;
}