CodeChefを充填する[ステイ]ピット - BLACKCOM(ツリーDP)

効果の件名:

ツリーを入力、リンク⼀サブ領域があるかどうかを尋ねる、S、Bの大きさは、黒い斑点を持っています。問い合わせの複数のセット、5000≤点Nの数

ソリューション:

ツリーのバックパック。

そこ結論:S Lユニコムブロックまでのサイズは黒いドットがRまで含まれている黒のドットを、含まれている場合、サイズはS、ユニコム黒のドットを備えるL〜Rブロックとして構成することができます

彼らはどこから来たしかし、この結論は知りません。

ように配置\(DP [X] [S ] \) で表される\(X \)根の大きさである\(S \)サブツリー最も/少なくとも黒点の数を含む、どのようなツリーリュック

時間複雑\(O(N ^ 2) \) 私はそれを許さないだろう

コード:

#include <bits/stdc++.h>
#define N 5010
#define inf 99999999
using namespace std;

int head[N],mrk[N],f[N][N],g[N][N],l[N],r[N],cnt,sz[N];

struct ed{
    int v,nxt;
}e[N<<1];
void add(int u,int v){
    e[++cnt]=(ed){v,head[u]},head[u]=cnt;
    e[++cnt]=(ed){u,head[v]},head[v]=cnt;
}

void dfs(int x,int fa){
    f[x][1]=g[x][1]=mrk[x];
    sz[x]=1;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].v;
        if(to!=fa){
            dfs(to,x);
            for(int j=sz[x];j>=1;--j)
                for(int k=sz[to];k>=1;--k){
                    f[x][j+k]=max(f[x][j]+f[to][k],f[x][j+k]);
                    g[x][j+k]=min(g[x][j]+g[to][k],g[x][j+k]);
                }
            sz[x]+=sz[to];
        }
    }
    for(int i=1;i<=sz[x];++i){
        l[i]=min(g[x][i],l[i]);
        r[i]=max(f[x][i],r[i]);
    }
}

void solve(){
    int a,b,i,n,q,j;
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;++i){
        l[i]=inf,r[i]=-inf;
        head[i]=mrk[i]=0;
        for(j=1;j<=sz[i];++j)
            f[i][j]=-inf,g[i][j]=inf;
        sz[i]=0;
    }   
    for(i=1;i<n;++i){
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    for(i=1;i<=n;++i) scanf("%d",&mrk[i]);
    dfs(1,0);
    while(q--){
        scanf("%d%d",&a,&b);
        if(l[a]<=b && b<=r[a]) puts("Yes");
        else puts("No");
    }
    cnt=0;
}

int main(){
    int T;scanf("%d",&T);
    memset(f,-1,sizeof(f));
    memset(g,0x3f,sizeof(g));
    while(T--) solve();
}

おすすめ

転載: www.cnblogs.com/PsychicBoom/p/11094172.html