HDU多校2020 第八场 1012/6866--Linuber File System(树上DP

题意:http://acm.hdu.edu.cn/showproblem.php?pid=6866

每个节点都有值域区间,一开始每个点值都为0,你每次可以选一个子树都+x,-x,0(任意),问最终所有节点满足值域的最小操作次数。

思路:

dp开二维,第二维计个值域区间,n方瞎搞搞就行,场上明显榜被带歪了,签到题水平(狗头)

代码有改动,可能不AC

int a[N],b[N],vl[N],vr[N];
int LS(int n)
{
    int m=0;
    for(int i=1;i<=n;++i)
        b[++m]=a[i];
    sort(b+1,b+1+m);
    m=unique(b+1,b+1+m)-b-1;
    for(int i=1;i<=n;++i)
        a[i]=lower_bound(b+1,b+1+m,a[i])-b;
    return m;
}
int top;
int dp[2010][8010];
void dfs(int u,int f)
{
    for(int i=1;i<=top;++i)dp[u][i]=0;
    for(int i=head[u];i;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==f)continue;
        dfs(to,u);
        for(int j=1;j<=top;++j)dp[u][j]+=dp[to][j];
    }
    int L=vl[u]*2,R=vr[u]*2;
    if(L>R)swap(L,R);
    int min_=INF;
    for(int i=L;i<=R;++i)min_=min(min_,dp[u][i]);
    for(int i=1;i<=top;++i)
    {
        if(i<L||i>R)
        {
            dp[u][i]=1+min_;
        }
        else
        {
            if(dp[u][i]!=min_)
                dp[u][i]=1+min_;
        }
    }
}

void solve()
{
    int n;
    cin>>n;
    Init(n);
    for(int i=1;i<n;++i)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    for(int i=1;i<=n+n;++i)cin>>a[i];
    a[n+n+1]=0;
    top=LS(n+n+1);
    for(int i=1,j=1;i<=n+n;i+=2,++j)
        vl[j]=a[i],vr[j]=a[i+1];
    top=top*2+1;
    dfs(1,0);
    int ans=dp[1][a[n+n+1]*2];
    cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/--HPY-7m/p/13498547.html