偷天换日
//T2 偷天换日
//dp还是最短路?
//其实就是二叉树形套了个背包?
//分成两块,左右子树,展厅里跑DP
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx=700;
int n;
int nn=1;
ll w[mx*mx];
ll c[mx*mx];
ll f[mx][mx];//f[i][j] 以i为根,用时j的最大价值
void dfs(int rt){
ll t;
int x;
scanf("%lld%d",&t,&x);
t=t*2;//细节
if(x>0){
for(int i=1;i<=x;++i){
scanf("%lld%lld",&w[i],&c[i]);//价值w,用时c
}
for(int i=1;i<=x;++i){
for(int j=n;j>=c[i]+t;--j){//写上面还快一点
f[rt][j]=max(f[rt][j],f[rt][j-c[i]]+w[i]);
// printf("f[%d][%d]=%lld\n",rt,j,f[rt][j]);
}
}
}
else {
/* nn++;
dfs(rt+1);
nn++;
dfs(rt+2);*/
nn++;
int ls=nn;
// printf("nn=%d rt+1=%d\n",nn,rt+1);
dfs(nn);
nn++;
int rs=nn;
dfs(nn);
//关于为什么不能用rt+1,rt+2
//因为它是按照深度优先给的输出,所以我们边深度优先边建树
//在建树的时候
//一的左右儿子可不是2 3 而是2 2深完了之后的值+1 是它,所以得用nn
//左右子树开始轮时间
//最后确认一次,树形DP,左右子树轮时间
//当到达叶子节点,用背包计算值,然后回溯
//这样还是只能说,只是一个思路感觉,有什么细节我也不知道,写吧。。。
//总时间是n-t
//f[rt][]
//为什么,用rt+1会爆,而ls,rs不会,我怎么也想不到是这错了
for(int i=t;i<=n;++i){
for(int j=0;j<=i-t;++j){
//轮的是时间,所以j直接0到i就行
//不对不对
f[rt][i]=max(f[rt][i],f[ls][i-j-t]+f[rs][j]);
// printf("1k f[%d][%d]=%lld n-t=%d\n",rt,i+j,f[rt][i+j],n-t);
}