树形DP中的实用卡空间技巧——洛谷P4438 [HNOI/AHOI2018]道路
若DP统计答案时是自下而上的,则两个子节点在这个节点统计完答案后就用不上了,所以我们可以设x的dfs序为dfn,左儿子的为dfn+1,右儿子dfn+2。这样计算出的结果除了根节点和少数节点外,其他节点的答案都是错的
适用于只用知道根节点的DP值且从下至上更新答案的情况
具体代码如下
#include<bits/stdc++.h>
using namespace std;
#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define fo(i,a) for(int i=0;i<a;++i)
const int inf=0x3f3f3f3f,N=4e4+10;
typedef long long ll;
int n,ls[N],rs[N],a[N],b[N],c[N];
ll dp[100][50][50];
inline void read(int &x){
x=0;char c=getchar(),f=1;
while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
x*=f;
}
void dfs(int u,int x,int y,int id){
if(u>=n){
go(i,0,x)
go(j,0,y)
dp[id][i][j]=1ll*c[u]*(a[u]+i)*(b[u]+j);
return;
}
dfs(ls[u],x+1,y,id+1),dfs(rs[u],x,y+1,id+2);
go(i,0,x)
go(j,0,y)
dp[id][i][j]=min(dp[id+1][i+1][j]+dp[id+2][i][j],dp[id+1][i][j]+dp[id+2][i][j+1]);
}
int main(){
read(n);
int x,y;
go(i,1,n-1){
read(x),read(y),x=(x<0)?(-x+n-1):x,y=(y<0)?(-y+n-1):y;
ls[i]=x,rs[i]=y;
}
go(i,n,2*n-1) read(a[i]),read(b[i]),read(c[i]);
dfs(1,0,0,1);
printf("%lld",dp[1][0][0]);
return 0;
}