Codeforces 1324 F.最大ホワイトサブツリー(木DP)/コメント

F.最大ホワイトサブツリー
TEST2の秒あたりの制限時間
test256メガバイトあたりのメモリ制限
入力inputstandard
outputstandard出力
あなたは、n個の頂点から成る木を与えています。木は、n-1のエッジに接続無向グラフです。(頂点vが黒である場合、頂点vが白と0であれば、AV = 1)このツリーの各頂点vは、それに割り当てられた色を有しています。

あなたは、各頂点vのために、以下の問題を解決する必要があります:白の数とあなたが頂点vが含まれている与えられた木のいくつかのサブツリーを選択した場合、あなたが得ることができ、黒の頂点の数との間の最大の違いは何ですか?ツリーのサブツリーは、与えられた木の接続部分グラフです。あなたはcntw白頂点とCNTB黒の頂点を含むサブツリーを選択した場合より正式に、あなたはcntw-CNTBを最大化しなければなりません。

入力
ツリー内の頂点の数-入力の最初の行は1個の整数N(2≤n≤2⋅105)を含みます。

Aiはi番目の頂点の色であり、入力の2行含まnは整数A1、A2、...、(0≤ai≤1)。

次のn-1ラインの各々は、ツリーのエッジを記述する。私は2つの整数のUIおよびVI、それが接続する頂点(1≤ui、vi≤n、UI≠VI)の標識によって示されるエッジ。

与えられたエッジがツリーを形成することが保証されています。

出力
印刷N RESI頂点Iを含有するいくつかのサブツリー内の白と黒の頂点の数との間の可能な最大の差である整数RES1、RES2、...、RESN、。


inputCopy
9
0 1 1 1 0 0 0 0 1
1 2
1 3
3 4
3 5
2 6
4 7
6 8
5 9
outputCopy
2 2 2 2 2 1 1 0 2
inputCopy
4
0 0 1 0
1 2
1 3
1 4
outputCopy
0 -1 1 -1

問題の意味:
n個の点を考えると、カラーの各点と、n-1辺は、偶数ツリー/無根木を確実にするためにエッジ。
各点を求めて、白色-cntブラックCNT最大接続サブグラフれます。

アイデア:

  1. クラシックツリーdpが、大物は、私は崩壊を書くために最後の夜複数の変更根菜ですので、これはテンプレートの問題であると言います。
  2. 個人的な習慣は、uがvはノードを示し、現在のノードを表します。
  3. サブツリーをトラバースするとき無根樹、そして、もちろん、明らかにルートノードにリーフノードに押された解答のIルートとするサブツリーに貢献を記録するために、CNTアレイが、ポイントのDFSを選択することで、あります最初のDFSして、ステータスを更新。
  4. 状態遷移は明らかである:CNT [U] + = MAX(0、CNT [V])。//サブツリー内の更新
  5. DFSは、私は答えアレイDPを記録するために使用されるルート、後に再び変化し始め、DPアレイは、2つの部分を含み、一方の部分は、[i]は寄与DPをルートIサブツリーであり、他の部分は、外側部分木であります答えの寄与の顔は、私たちは、サブツリーの外側の部分のルートを変更する際に計算する必要があります。
  6. vはサブツリーのルートノードである場合= CNT [V]、CNTので、[U]一時的に発現される - [U]は、CNTに寄与するサブツリーを横切る、もしCNT [V] CNTの[U]必要外部貢献し、この時点で状態遷移が明らかになる:CNT [V] + = MAX(0、CNT [U])。//子ツリーの外側を更新
  7. そして、CNT [V]とCNT [U]反発、なぜなら我々は、配列CNTとサブツリーの貢献を記録したときにのみ、バックトラックに覚えています。
  8. 詳細は、それを見るために〜コード
  9. 何でもウェルカムメッセージ交換のプライベートの手紙についての不明確な話であれば〜

コード:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define ins insert
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#pragma GCC optimize(2)
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("YES") ;}void put2(){ puts("NO") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}ll Inv(ll x,ll p){return qp(x,p-2,p);}
ll Cal(ll n,ll m,ll p){if (m>n) return 0;ll ans = 1;for(int i = 1; i <= m; ++i)
ans=ans*Inv(i,p)%p*(n-i+1)%p;return ans%p;}

const int manx=2e5+5;

ll col[manx],vis[manx],dp[manx],cnt[manx];
vector<ll>g[manx];
ll cnt1=0,cnt2=0,n,top;

void dfs(ll u){
    vis[u]=1;
    cnt[u]=(col[u]==1?1:-1);
    for(auto v: g[u]){
        if(vis[v]) continue;
        dfs(v);
        if(cnt[v]>0) cnt[u]+=cnt[v];
    }
}
void dfs1(ll u){
    dp[u]=cnt[u]; vis[u]=1;
    for(auto v: g[u]){
        if(vis[v]) continue;
        if(cnt[v]>0) cnt[u]-=cnt[v];
        if(cnt[u]>0) cnt[v]+=cnt[u];
        dfs1(v);
        if(cnt[u]>0) cnt[v]-=cnt[u];
        if(cnt[v]>0) cnt[u]+=cnt[v];
    }
}
int main(){

    n=read();
    for(int i=1;i<=n;i++) col[i]=read(),f[i]=i;
    for(int i=1;i<n;i++){
        ll u=read(),v=read();
        g[u].pb(v),g[v].pb(u);
    }
    dfs(1);
    for(int i=1;i<=n;i++) vis[i]=0;
    dfs1(1);
    for(int i=1;i<=n;i++)
        printf("%lld ",dp[i]);
    return 0;
}
公開された76元の記事 ウォン称賛43 ビュー20000 +

おすすめ

転載: blog.csdn.net/JiangHxin/article/details/104834074
おすすめ