首页 > 其他分享 >树形dp

树形dp

时间:2022-08-14 20:44:19浏览次数:79  
标签:sz int id 树形 次长 最长 dp

## 1.换根dp

1.kamp

首先肯定它是换根dp

因为最后一次不用回到起点,所以先不去想别的,最后再减去一个最长链

设g\([i],\)为以i为根前往在这颗子树中的家的最小距离

\(f[i],\)为以i为起点,送回家的最小花费;

首先对于\(g[i],g[u]= g[to]+2\times w;\)
\(sz[i]\)表示在i这颗子树中有多少家

考虑dp:
\(1.sz[to]=0,\)那么\(f[to]=f[u]+2 \times w;\)
\(2.sz[to]=K,\)那么\(f[to]=g[to]\)
\(3.f[to]=f[u]\)

考虑维护最长链,因为之前已经维护好了以1位根的子树中的最长和次长,考虑换根情况下子树之外的最长链

如果to是最长链上的,那么这个链不就废了,所以还需要维护一个次长链

第一种情况下:\(L[to]=L[u]+w;\)之前在维护子树内链的时候,只有sz[i]!=0,才更新,并且L[u]中也包含了子树外的情况,所以正确
第二种情况下:不用维护,本来就是子树内

第三种情况:
u的最长链去更新to的最长链,必须保证to不在最长链上
u的次长链去更新to的最长链
u的最长链去更新to的次长链,必须保证to不在最长链上
u的次长链去更新to的次长链
考虑到u与to相连,所以id[i]记录一下最长链经过的第一个节点。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+10;
#define int long long 
typedef double db;
int n,K;
int head[N],len,sz[N],g[N],f[N],L[N],l[N],id[N];
/*维护最长、次长链 以及最长链经过的第一个节点*/
bool vis[N];
struct node{
    int from,to,next,w;
}e[N<<1];
int read(){
    int res=0,l=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')l=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*l;
}
struct Graph{    
    void add(int from,int to,int w){
        e[++len].from=from;
        e[len].to=to;
        e[len].w=w;
        e[len].next=head[from];
        head[from]=len;
    }
    void dfs(int u,int fe){
        if(vis[u])sz[u]=1;
        for(int i=head[u];i;i=e[i].next){
            int to=e[i].to;
            if(to==fe)continue;
            dfs(to,u);
            int w=e[i].w;
            if(sz[to]){
                g[u]+=g[to]+2*w;
                int NEW=L[to]+w;
                if(NEW>=L[u]){
                    l[u]=L[u],L[u]=NEW,id[u]=to;
                }else if(NEW>l[u])l[u]=NEW;
            }
            sz[u]+=sz[to];
        }
    }
    void dp(int u,int fe){
        for(int i=head[u];i;i=e[i].next){
            int to=e[i].to;
            if(to==fe)continue;
            int w=e[i].w;
            if(!sz[to])f[to]=f[u]+2*w,L[to]=L[u]+w;
            else if(K-sz[to]){
                f[to]=f[u];
                if(id[u]!=to&&L[u]+w>=L[to]){l[to]=L[to];L[to]=L[u]+w;id[to]=u;}
                else if(l[u]+w>=L[to]){l[to]=L[to];L[to]=l[u]+w;id[to]=u;}
                else if(id[u]!=to&&L[u]+w>=l[to])l[to]=L[u]+w; 
                else if(l[u]+w>=l[to])l[to]=l[u]+w;
            }else f[to]=g[to];
            dp(to,u);
        }
    }
}G;
signed main(){
    cin>>n>>K;
    for(int i=1;i<n;++i){
        int a,b,c;
        cin>>a>>b>>c;
        G.add(a,b,c);
        G.add(b,a,c);
    }
    for(int i=1,a;i<=K;++i)cin>>a,vis[a]=1;
    G.dfs(1,0);
    f[1]=g[1];
    G.dp(1,0);
    for(int i=1;i<=n;++i)printf("%lld\n",f[i]-L[i]);
    return 0;
}

貌似换根dp都需要维护最长和次长链

2.平衡树

标签:sz,int,id,树形,次长,最长,dp
From: https://www.cnblogs.com/zasdcn/p/16586261.html

相关文章

  • 数位DP-2出现的次数
    问题描述编写一个方法,计算从0到n(含n)中数字2出现的次数。示例:输入:25输出:9解释:(2,12,20,21,22,23,24,25)(注意22应该算作两次)提示:n<=10......
  • 拉格朗日插值优化DP
    拉格朗日插值优化DP模拟赛出现神秘插值,太难啦!!回忆拉格朗日插值是用来做什么的对于一个多项式\(F(x)\),如果已知它的次数为\(m-1\),且已知\(m\)个点值,那么可以得到\[F(k......
  • P7154 [USACO20DEC] Sleeping Cows P(DP)
    主要是状态设计比较难想,但其实可以理性地推出来。P7154[USACO20DEC]SleepingCowsP考虑最终一个合法状态是怎么样的:一定是一堆小牛棚,一堆大奶牛,最大的牛棚小于最小的......
  • P6144 [USACO20FEB]Help Yourself P(DP+线段树)
    P6144[USACO20FEB]HelpYourselfP将线段按照了\(r\)排序,设右端点为\(r\)的答案为\(f_r\),发现这样转移非常困难。\(\color{yellow}{\bigstar\texttt{Trick}}\):区间......
  • CF559E Gerald and Path(DP)
    CF559EGeraldandPath设\(dp(i,p)\)表示完成前\(i\)条线段的覆盖,最右端位于\(p\)点的最大收益。转移?向下一条线段转移时加上他们中间的距离?发现这样没有办法统计......
  • CF856D Masha and Cactus(树上 DP+抵消贡献技巧)
    CF856DMashaandCactus我们先捞出一个根节点,那么一次旋变就是对路径上点的覆盖。设\(dp_{i,0}\)表示\(i\)没有选择时子树内最大收益,\(dp_{i,1}\)表示\(i\)选择......
  • CF512D Fox And Travelling(DP 计数)
    CF512DFoxAndTravelling给定一张\(n\)个点\(m\)条边的无向图,每次选择一个叶子结点并将它和连接它的边删除。对于每个\(k\in[0,n]\),问有序选择\(k\)个点的方案......
  • 【杂题乱写】AtCoder dp 26题
    AtCoderdp26题原比赛链接洛谷题单链接A-Frog1题目已然给出了转移方程,设\(dp_i\)为到第\(i\)块石头的最小代价。转移方程:\[dp_i=\min(dp_{i-1}+|h_i-h_{i-1}......
  • 【$dp$】$\text{LuoguP6570}$ 优秀子序列
    \(\text{LuoguP6570}\)优秀子序列读完题大概能yy到一个转移,即枚举两个不相交的子集然后转移。其实这题的顺序都无所谓,应该排个序,或者直接在值域上操作。\(DP\),用\(f......
  • 数位Dp
    代码拍卖会题意问有[L-R]有多少个数满足每一位都至少有1,从左到右不减同时要能被P整除,位数<=\(1e18\).p<=500)思路位数贼大,基本上别想着枚举有关位数的东西单调......