[BZOJ3257]パズルツリー

[BZOJ3257]パズルツリー

無根樹を与えます。ツリーはN点、右辺の値を有します。各点は色、黒、白、あるグレー三色を有し、三色ツリーと呼ばれます。

アリス、三色平衡ツリーは、場合にのみ、ツリーノードが黒又は最大で含む白色ノードが含まれていないことを美しいです。しかし、与えられた3色の木は、このプロパティを満たさない場合があります。だから、アリスが各ツリーがバランスされた森を形成するように、いくつかの側面を削除するつもりで、価格は和の右側を削除するコストに等しいです。あなたが最小である過ごすために必要な価格を計算してください。複数のデータセット。N <= 3E5


私は非常に明白に感じます

ステータスセット\(DP \ [I] \ [0/1] [0/1/2] \) 0/1/2は白点を有する、I-高速通信リンクが黒点0/1を有し表し、前記それはプロセスとみなす黒ドットよりも大きい二つ白処理とみなす以上2点、グレー点は問題ではない、それが回答に影響を与えない状態で含まれていません

便宜上、表記X1 = 0/1×2 = 0/1/2が第三の次元を表し、第二の寸法を示しています

もともと私はまだ、ハングアップ兄のアプローチを見てuは混乱の多くを書い色従います。

2例を考えてみます。現在は、uは/保持を切り取ります

検討する良いケースを保管してください:列挙Vの前にX1、X2およびV X1、X2、直接転送

詳細は、2×1秒の次元のために、私たちは願って、事を言います

= 1 + 0 = 1 0 + 1,1 + 1 = 1

だから、2×1またはアップライン上。

X2の場合は、ライン上で何か> 2つのリターン2を書くための良い方法ではありません

予約転送方程式:
\ [Cminの(DP [U] [X1 | Vx1は] [T(X2 + VX2)]、DP [U] [X1] [X2] + DP [V] [Vx1は] [VX2])\ ]
の条件が満たされるべきである場合、それは正当なサブツリーはV次いで、切断

次に
\ [CMIN(DP [U]
[X1] [X2]、DP [U] [X1] [X2] + DP [V] [VX1] [VX2] + W)\] それぞれについて同じである、個転送し、次にDPをカバーする新しい配列[U]で、Vを挙げ


#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=x;i<=y;i++)
using namespace std;
typedef long long ll;
const int maxn=300010;
const ll inf=1LL<<62;
struct Edge{
    int v,nex,dis;
}edge[maxn<<1];
int cnt,head[maxn],col[maxn],n;
ll dp[maxn][5][5],f[5][5];
void addEdge(int u,int v,int d){
    edge[++cnt]=(Edge){v,head[u],d};head[u]=cnt;
}
/*
dp[x][0/1][0/1/2]表示与x相连的连通块中
有0或多个黑,0个,1个或多个白 的答案
*/
inline int XT(int x){
    return x>2?2:x;
}
inline void cmin(ll &x,ll y){
    if (y<x) x=y;
}
void dfs(int u,int fa){
    dp[u][col[u]==0][col[u]==1]=0;
    for (int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v,w=edge[i].dis;
        if (v==fa) continue;
        dfs(v,u);
        rep(x1,0,1) rep(x2,0,2) f[x1][x2]=inf;
        rep(x1,0,1) rep(x2,0,2) if (dp[u][x1][x2]<inf)
            rep(vx1,0,1) rep(vx2,0,2) if (dp[v][vx1][vx2]<inf){
                cmin(f[x1|vx1][XT(x2+vx2)],dp[u][x1][x2]+dp[v][vx1][vx2]);
                if ((vx1==0) || vx2<2) cmin(f[x1][x2],dp[u][x1][x2]+dp[v][vx1][vx2]+w);
            }
        memcpy(dp[u],f,sizeof(dp[u]));
    }
}
int read(){
    int x=0;char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) x=x*10+ch-48,ch=getchar();
    return x;
}
int main(){
    int T=read();
    while (T--){
        rep(i,1,maxn-1) rep(x1,0,1) rep(x2,0,2) dp[i][x1][x2]=inf;
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        memset(col,0,sizeof(col));
        cnt=0;
        n=read();
        rep(i,1,n) col[i]=read();
        rep(i,1,n-1){
            int x=read(),y=read(),d=read();
            addEdge(x,y,d);addEdge(y,x,d);
        }
        dfs(1,0);
        ll ans=inf;
        rep(x2,0,2) ans=min(ans,dp[1][0][x2]);
        rep(x2,0,1) ans=min(ans,dp[1][1][x2]);
         printf("%lld\n",ans);
    }
    //getchar();
    return 0;
}

鍋を修復するためにリフレクションと:

1、注意を払っていない理由は、保持時間は、DPする[U] [X1] [X2]とDP [V] [VX1] [VX2]とするとき、それは正当なのですか?

転送が明確、ああ呼び出さない式感じている場合2、カットオフ\(DP [U] [X1] [X2] + DPを[V] [VX1] [VX2] \ W +)常に感じ> DP [ U] [X1] [X2] 、私は理由を転送します分からないのですか?

おすすめ

転載: www.cnblogs.com/ugly-CYW-lyr-ddd/p/11802245.html