[羅区P4107] HEOI2015バニーと桜

問題の説明

長い、長い時間前に、森はウサギのグループに家です。ある日、ウサギは突然桜を見ることにしました。ウサギの森は非常に特別である桜の木。n-1個の枝により接続されている0からN-1までの番号ポイント、n個の分岐点を分岐Nブランチにより桜の木は、我々は、ノードが0である、ルート付きツリー構造としてそれを見ることができますルートノード。このツリーの各ノードは、i番目のノードがC_I桜の花を持って、そのうちのいくつかの桜があります。各ノードは、各ノードI、その子ノードiはチェリー及びMの数を超えることができないノードの数、すなわち、息子(I)+ C_I <= mに対して、最大桜負荷mを有します息子前記(i)はiが葉ノードである場合、息子(i)は= 0、子Iの数を表します。

今、私はいくつかのノードを削除することを望んで、あまりにも多くのウサギの桜の木のノードを考えます。ノードが除去されると、ノードのチェリー及びその息子のノードが削除されたノードの親ノードに接続されています。親ノードも削除されている場合は、最初のノードが削除されていないアップまで、アップ接続していきます。

今、私たちは、ノードの数を削除するまでの最大荷重に違反することなく、ウサギで計算します。

ルートが削除されないことに注意してください、削除されたノードは、負荷に含まれていません。

入力形式

最初の入力2つの正の整数の行、nおよびmは、それぞれのノードの数と最大負荷を表します

二行目のn整数C_I、桜は、i番目のノードの数を表します。

最初の番号の次のn行は、子の数がこのノード、息子の整数を表しK_I次のノードを示すK_I

出力フォーマット

ノードの最大数を表す線の整数を削除することができます。

サンプル入力

4 10
0 2 2 2 4 1 0 4 1
3 6 2 3 4
1 9
1 8
1 1
0
0
2 7 4
0
1 5
0

サンプル出力

4

データ範囲

データの30%、1 <= N <= 5000、1 <= M <= 100、0 <= C_I <= 100

データの70%を、1 <= N <= 200000、1 <= M <= 2000、0 <= C_I <= 1000

データの100%、1 <= N <= 2000000、1 <= M <= 100000、0 <= C_I <= 1000

その初期データを確実にするために、ノードのチェリー息子の数に各ノードの数が0より大きく、Mを超えません

解決

ノードの祖先には影響しないノードを削除する方法を、見つけることができます。そこで、我々は、下から上へ順番にノードを通過することができます。セット([I] =息子ワット\ [i]が+ C [i]が\) 父の増加になる価格・ポイントを削除することを意味する([i]のワット\)\を負荷の。そう、貪欲な戦略は、これまでの彼の息子まで削除することができない点ごとに大きな欠失に小型の考慮があります。ノードのコストを削除し、更新します。

そうする権利である理由の質問です。以下は、この貪欲な戦略は後に効果持っているか否かについての簡単な議論です。彼の息子があまりにも肥大化になるので、あなたはポイントを削除した場合、我々は削除しないことを選択することができ小さな兄弟の彼のコストを変更するには、彼を削除し、最適な答えに与える影響はありませんでした。だから、何の後の効果はありません。

コード

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define N 2000002
using namespace std;
vector<int> v[N];
int head[N],ver[N*2],nxt[N*2],l;
int n,m,i,j,c[N],son[N],w[N],ans;
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;
}
int my_comp(const int &x,const int &y)
{
    return w[x]<w[y];
}
void dfs(int x)
{
    w[x]=son[x]+c[x];
    for(int i=head[x];i;i=nxt[i]){
        dfs(ver[i]);
        v[x].push_back(ver[i]);
    }
    sort(v[x].begin(),v[x].end(),my_comp);
    for(unsigned int i=0;i<v[x].size();i++){
        int y=v[x][i];
        if(w[x]+w[y]-1<=m){
            ans++;
            w[x]+=w[y]-1;
        }
        else break;
    }
}
int main()
{
    n=read();m=read();
    for(i=1;i<=n;i++) c[i]=read();
    for(i=1;i<=n;i++){
        son[i]=read();
        for(j=1;j<=son[i];j++){
            int x=read()+1;
            insert(i,x);
        }
    }
    dfs(1);
    printf("%d\n",ans);
    return 0;
}

ヒント

貪欲な戦略は、それを削除することはできませんまで、ボトムアップからの各点のコストの息子を削除することです。

実際に、私は完全に貪欲な戦略を考えてきたが、損失が得られる利益より大きくなりませんので、この戦略は、本質的に間違って後遺症です。結論、の後遺症についての質問には、次の確認ではなく、あなたのズボンのラフ席の前について慎重に検討する必要があります。

おすすめ

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