タイトル
図無向\(G \)有していて\(N- \)点、\(1-N- \)エッジを。点から\(1 \)の\(N- \)を順次として、番号が付けられている(I \)\右のポイント値\(W_i \) 、各辺の長さがあり、\(1 \) 。二点で\((u、v)は\ ) の距離として定義される\(U \)をポイント\(V \)最短距離点。図ため(G \)\上の点\((U、V)\) 、その距離がある場合\(2 \) 、次いで生成その間\(W_v \回W_u \)合計重量。
ウィル図\(G \)最大重量上のすべての生産共同発注のポイントは、米国の重みをどのくらいですか?すべての関節の重みの和とどのくらい?
分析のトピック
図無向\(G \)有していて\(N- \)点、\(1-N- \)エッジを。
明らかに、与えられたことを無根樹
すべての組合権と値が大きいかもしれないので、あなたはそれを出力したいときに\(10007 \)を引き継ぐために。
エラーが発生しやすい箇所、フィルムを取ることなく、最大値、およびちょうどフィルムを取得したいです。
分析
彼はルートレスの木ですので、我々としても彼に与えるかもしれない確認\(1 \)ルートノードのために。
彼は長い間、各ポイントの対価として、木なので\(3 \)の場合:親の親の(祖父)、彼の息子の子ノード、および父親と、彼はすべてのポイントがある(孫)
各ポイントで、その後、見つけることができますが、無視することができ、子ノードの計算された子ノードそれぞれの親の親演算子の値である限り、対応をカウント2回その上に。
ここで少し説明:(自動的にスキップ人々の理解を)
セット\(X \)親親ノードである(Y \)\。
オペレータ\(X \)の場合は、であることが第一ケース(親ノードの親)を探している\(w_x w_y * \) 。演算子\(Y \)が、また、に状況秒ケース(子子ノード)が再びカウント(w_y * w_x \)\。
あなたが安全に二ケースを無視することができますので、最初の例の結果は乗じた(2 \)\。
まあ続けます。
完全な分析だから、あなたは直接実行することができます\(DFS \) 。
各点について、直接見なさ最初のケース(直接乗算);後者の場合、直接列挙彼らは同じ父を持ち、全ての点が、答えは常に更新することができます。
少し小さな最適化(私は考えずに生きることができました)
直接\(DFS \)直接TLEは、また、最適化の少しを必要とします。
ただ、すべての時間は右の点の列挙の前処理にあることが判明し、最終的な結論を見てください。
セット\(和[X] \)を表す点を(X \)\すべての子ノードと右点。
ポイントの最大値\(X-は\) 、また彼の子ノード得られた最大値と二番目に大きいです。(次の層の最大点があるので、それ自体を掛けることができません)
そして、その上に。
いくつかは理解していない場合は、コードを見ることができます。
- コード
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int dalao=10007;
struct edge{
int v,nx;
}p[400005];
int n,ne,f[200005];
int sum[200005],father[200005],w[200005];
int data[200005][2],gmax[200005][2];//data记录编号 gmax记录具体值 0最大值 1次大值
int maxn,ans;
void read(int u,int v)
{ p[++ne].v=v;
p[ne].nx=f[u];
f[u]=ne;
}
void getfather(int x,int fa)
{ father[x]=fa;
for(int i=f[x];i;i=p[i].nx)
{ if(p[i].v==fa)continue;
getfather(p[i].v,x);
}
}
int main()
{ scanf("%d",&n);
for(int i=1;i<n;i++)
{ int u,v;
scanf("%d%d",&u,&v);
read(u,v);
read(v,u);
}
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
sum[0]=w[1];
getfather(1,0);//确认每个点的父节点
for(int i=1;i<=n;i++)//预处理
for(int j=f[i];j;j=p[j].nx)
{ if(p[j].v==father[i])continue;
sum[i]=(sum[i]+w[p[j].v])%dalao;//预处理和
//预处理最大值和次大值
if(w[p[j].v]>gmax[i][0]){gmax[i][0]=w[p[j].v];data[i][0]=p[j].v;}
else if(w[p[j].v]>gmax[i][1]){gmax[i][1]=w[p[j].v];data[i][1]=p[j].v;}
}
for(int x=1;x<=n;x++)
{ if(father[father[x]])//存在父节点的父节点
ans=(ans+2*w[x]*w[father[father[x]]])%dalao;
if(father[father[x]])
maxn=max(maxn,w[x]*w[father[father[x]]]);
ans=(ans+w[x]*(sum[father[x]]-w[x]))%dalao;
if(data[father[x]][0]!=x)maxn=max(maxn,w[x]*gmax[father[x]][0]);
else maxn=max(maxn,w[x]*gmax[father[x]][1]);
}
printf("%d %d\n",maxn,ans);
return 0;
}
\ [{Rainy7によって} \テキスト\]