共同重み[グループを改善NOIP2014-] - 問題の解決を

  • タイトル

    図無向\(G \)有していて\(N- \)点、\(1-N- \)エッジを。点から\(1 \)\(N- \)を順次として、番号が付けられている(I \)\右のポイント値\(W_i \) 各辺の長さがあり、\(1 \) 二点で\((u、v)は\ ) の距離として定義される\(U \)をポイント\(V \)最短距離点。図ため(G \)\上の点\((U、V)\) その距離がある場合\(2 \) 次いで生成その間\(W_v \回W_u \)合計重量。

    ウィル図\(G \)最大重量上のすべての生産共同発注のポイントは、米国の重みをどのくらいですか?すべての関節の重みの和とどのくらい?


  • 分析のトピック

    1. 図無向\(G \)有していて\(N- \)点、\(1-N- \)エッジを。

      明らかに、与えられたことを無根樹

    2. すべての組合権と値が大きいかもしれないので、あなたはそれを出力したいときに\(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によって} \テキスト\]

おすすめ

転載: www.cnblogs.com/Rainy7/p/12275983.html