"Big Tree dp"

<> Yes

<First update>


<Text>

Big

Description

Funny Funny fruit trees, trees you and me funny, funny tree before games, and more funny addition. Tree has n nodes, which constitute a tree, each node has a comical value.

A communication block is a large difference between the largest value and the minimum funny funny value does not exceed d.

Each time you can choose a large communication block and delete them, can I ask you at least a few of these nodes are deleted it?

Input Format

The first line of two integers d and n.

The second line n integers, respectively funny value for each node.

The next two rows each row n-1 represents an integer from one side.

Output Format

A row of integer answer.

Sample Input

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

Sample Output

2

Resolve

A thinking problem.

It looks like a tree \ (dp \) , but it seems difficult to maintain restrictions. But we can change the direction of a consideration, we have a right to the point \ (a [x] \) is treated as a node interval \ ([A [the X-], A [the X-] + d] \) , then a legitimate Unicom deletion block is bound to meet at least one common point is communication coverage within all sections of the block.

想到这个就可以\(dp\)了,设\(g[x]\)代表删除子树\(x\)的最小代价,\(f[x][v]\)代表以\(x\)为根的子树中还存在一个未结算删除代价的连通块,其公共点为\(v\)的最小代价和。状态转移方程:
\[f[x][v]=\sum_{y\in son(x)}\min\{f[y][v],g[y]\},g[x]=\min_{v\in[a[x],a[x]+d]}\{f[x][v]+1\}\]
第一个方程的含义就是要么直接删除一棵子树,要么连接到当前点的连通块里,待会一起删除。第二个方程的含义就是找一个公共点,然后在节点\(x\)处把未结算的代价结算掉,删除连通块。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 5020;
struct edge { int ver,next; } e[N*2];
int n,d,t,Head[N],a[N],f[N][N],g[N];
inline void insert(int x,int y) { e[++t] = (edge){y,Head[x]} , Head[x] = t; }
inline void input(void)
{
    scanf("%d%d",&d,&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        insert( x , y );
        insert( y , x );
    }
}
inline void dp(int x,int fa)
{
    for (int i=a[x];i<=min(a[x]+d,5000);i++)
        f[x][i] = 0;
    for (int i=Head[x];i;i=e[i].next)
    {
        int y = e[i].ver;
        if ( y == fa ) continue;
        dp( y , x );
        for (int j=a[x];j<=min(a[x]+d,5000);j++)
            f[x][j] += min( f[y][j] , g[y] );
    }
    for (int i=a[x];i<=min(a[x]+d,5000);i++)
        g[x] = min( g[x] , f[x][i] + 1 );
}
int main(void)
{
    input();
    memset( f , 0x3f , sizeof f );
    memset( g , 0x3f , sizeof g );
    dp( 1 , 0 );
    printf("%d\n",g[1]);
    return 0;
}

<后记>

Guess you like

Origin www.cnblogs.com/Parsnip/p/11447171.html