【ARC098F]寄付

問題の説明

n個の点を考慮すると、mは図自由縁。この図の各点は2点の重みがあるAIBIをあなたは出発点として、この図からポイントを選択し、この絵を横断を開始します。あなたは私があればノードに到達することができますし、少なくとも持っている場合にのみ、ドル。あなたはノードIに到達すると、あなたは、この点に寄付することを選択でき双方向元。あなたは、各ポイントのために一度寄付する必要があります。少なくとも、ドルの数を持ってあなたの体を頼みますか?

入力形式

最初の2つの数のラインN、M。

2つの数のn行は、BI愛。

2つの数のUIのMラインが、VI、UIは、一方の側からVIへの発現しました。

出力フォーマット

答えのための整数出力ライン。

サンプル入力

4 5
3 1
1 2
4 1
6 2
1 2
2 3
2 4
1 4
3 4

サンプル出力

6

解決

我々は唯一の時間がかかりますが、あなたはいつでも過ごすことができる時間の点を通過することに注意してください。そして、我々が各ポイントごとに繰り返さ通過することは明らかであるので、最後のパスで料金を支払う最適です。

したがって、我々はそのように、配列Cを作成し、制約を変更し\(C [I] =最大 ([I] -b [I]、0)\) 我々は、私はいつでもポイントを通過したことを意味し、手が少なくともなければなりません持っている\(C_I \)お金の量を。

私たちは、貪欲最初のトラバーサルと考えることができます\(C_I \)の最大のポイントは、このポイントを削除した後、我々は中国聯通ブロックの数を取得します。そして、最良の方法は、明らかに寄与している(C_I \)\リンクが出て、その後、もはや後のブロックに。

その後、我々に行くにも層上のサブルートツリーのルートを持つ層によって再帰層。我々は、すべての子のツリー構築することができるように\(C_I \)をツリーのルートよりも小さくなければなりません。

次いでDPを導く、\(F [X]は\) 金銭条件の最小の初期量を満たすxのサブツリーを表す\(S [X] \) xのb値のサブツリーを表し、それは完全な木サブを横切りますXで必要ツリーコスト(含まない\(C [X] \) )。\(F [X] \)初期値\(S [X] + C [X] \) の点xにおける最後の停止を表します。サブツリーは、状態遷移式で、最後の列挙トラバーサル
\ [F [X] =分 (F [x]は、S [X] -s [Y] [X] C] Y [F + MAX(、 ))\]

コード

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
#define N 100002
using namespace std;
int head[N],ver[N*2],nxt[N*2],l;
int head1[N],ver1[N*2],nxt1[N*2],l1;
int n,m,i,j,a[N],b[N],c[N],fa[N],p[N],f[N],sum[N];
bool vis[N];
int read()
{
    char c=getchar();
    int w=0;
    while(c<'0'||c>'9') c=getchar();
    while(c<='9'&&c>='0'){
        w=w*10+c-'0';
        c=getchar();
    }
    return w;
}
void insert(int x,int y)
{
    l++;
    ver[l]=y;
    nxt[l]=head[x];
    head[x]=l;
}
void insert1(int x,int y)
{
    l1++;
    ver1[l1]=y;
    nxt1[l1]=head1[x];
    head1[x]=l1;
}
int my_comp(const int &x,const int &y)
{
    return c[x]<c[y];
}
int find(int x)
{
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
void dfs(int x)
{
    sum[x]=b[x];
    for(int i=head1[x];i;i=nxt1[i]){
        int y=ver1[i];
        dfs(y);
        sum[x]+=sum[y];
    }
    f[x]=sum[x]+c[x];
    for(int i=head1[x];i;i=nxt1[i]){
        int y=ver1[i];
        f[x]=min(f[x],sum[x]-sum[y]+max(f[y],c[x]));
    }
}
signed main()
{
    n=read();m=read();
    for(i=1;i<=n;i++){
        a[i]=read();b[i]=read();
        c[i]=max(a[i]-b[i],1LL*0);
    }
    for(i=1;i<=m;i++){
        int u=read(),v=read();
        insert(u,v);
        insert(v,u);
    }
    for(i=1;i<=n;i++) fa[i]=p[i]=i;
    sort(p+1,p+n+1,my_comp);
    for(i=1;i<=n;i++){
        int x=p[i];
        vis[x]=1;
        for(j=head[x];j;j=nxt[j]){
            int y=ver[j];
            if(vis[y]){
                int f=find(y);
                if(f!=x){
                    fa[f]=x;
                    insert1(x,f);
                }
            }
        }
    }
    dfs(p[n]);
    cout<<f[p[n]]<<endl;
    return 0;
}

おすすめ

転載: www.cnblogs.com/LSlzf/p/11691098.html