BZOJ传送门
洛谷传送门
解析:
出这种无聊的空间优化题。。。出题人也真的是够了。
题意简述一下就是,一颗二叉树,对于每个叶子节点,设它到根的路径上需要经过的未被指定的左右向边数量分别为 L , R L,R L,R,则计算它的贡献为 c ( a + L ) ( b + R ) c(a+L)(b+R) c(a+L)(b+R)。
乍一看只能网络流,先%DZYO队爷,给出了这道题的网络流解法。
但是由于深度最多只有 40 40 40,所以 O ( ∑ d e p 2 ) O(\sum dep^2) O(∑dep2)的 D P DP DP就已经可以水过这道题了。
注意空间是卡不过去的。
有两个选择,
第一,发现这个树形DP只有从儿子向父亲的转移,就可以用一个栈来分配DP数组的内存,显然这样大深度只会达到 80 80 80,随便做。
第二,放弃所有叶子节点的DP数组,转用函数来返回需要的DP值,空间直接少一半,随便过。
我写的是动态分配DP数组。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
re bool f=0;
while(!isdigit(c=gc()))if(c=='-')f=1;re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
}
using namespace IO;
cs int N=2e4,M=4e4+4;
ll f[82][41][41];
int t[M],s[M],a[M],b[M],c[M];
int n;
int num[M],sta[M],top,tot;
void dfs(int u,int S,int T){
int p=num[u]=top?sta[top--]:++tot;
if(!s[u]){
for(int re i=0;i<=S;++i)
for(int re j=0;j<=T;++j)
f[p][i][j]=(ll)c[u]*(a[u]+i)*(b[u]+j);
return ;
}
dfs(s[u],S+1,T);dfs(t[u],S,T+1);
int lc=num[s[u]],rc=num[t[u]];
for(int re i=0;i<=S;++i)
for(int re j=0;j<=T;++j)
f[p][i][j]=min(f[lc][i][j]+f[rc][i][j+1],f[lc][i+1][j]+f[rc][i][j]);
sta[++top]=lc;
sta[++top]=rc;
}
signed main(){
n=getint();
for(int re i=1;i<n;++i){
s[i]=getint();
t[i]=getint();
if(s[i]<0)s[i]=n-1-s[i];
if(t[i]<0)t[i]=n-1-t[i];
}
for(int re i=n;i<=2*n-1;++i)a[i]=getint(),b[i]=getint(),c[i]=getint();
dfs(1,0,0);
cout<<f[1][0][0];
return 0;
}