在网上翻了几篇博客没看懂,自己强行开码,于是就写篇博客希望对别的“走投无路”的人有所帮助
心路历程:
普及+的题目,不知道当时自己在想什么,dp式倒是推对了,然而优化不了空间,惨痛RE,然后钦定HNOI凉凉
题意:
设叶子结点到根结点,会经过i条未翻修的公路,j条未翻修的铁路
则叶子结点到根结点的贡献为 c[i]∗(a[i]+i)∗(b[i]+j) c [ i ] ∗ ( a [ i ] + i ) ∗ ( b [ i ] + j )
设计方案控制 i,j i , j 使 ∑叶子结点ic[i]∗(a[i]+i)∗(b[i]+j) ∑ 叶 子 结 点 i c [ i ] ∗ ( a [ i ] + i ) ∗ ( b [ i ] + j ) 最小
Solution
设 f[u][i][j] f [ u ] [ i ] [ j ] 表示从根结点到结点u经过 i i 条未翻修公路,条未翻修铁路
的贡献最小值
于是有针对叶子结点(乡村),先预处理出
然后是城市点 u u
当选择修公路时,则右儿子会多经过一条未修的铁路
同理,当
u−>v
u
−
>
v
选择修铁路时,则左儿子会多经过一条未修的公路
所以最终二者取
min
m
i
n
f[u][i][j]=min(f[lson][i][j]+f[rson][i][j+1],f[lson][i+1][j]+f[rson][i][j]);
f
[
u
]
[
i
]
[
j
]
=
m
i
n
(
f
[
l
s
o
n
]
[
i
]
[
j
]
+
f
[
r
s
o
n
]
[
i
]
[
j
+
1
]
,
f
[
l
s
o
n
]
[
i
+
1
]
[
j
]
+
f
[
r
s
o
n
]
[
i
]
[
j
]
)
;
然后是值得注意的细节
1.
f[u][i][j]
f
[
u
]
[
i
]
[
j
]
开
longlong
l
o
n
g
l
o
n
g
,然后中间叶子结点相乘时开1LL
2.本题卡空间,
f[u][i][j]
f
[
u
]
[
i
]
[
j
]
中的一维
u
u
是不能开到20000的,这显然MLE,但是我们注意到上述dp再处理过程中,是一定先把儿子处理完才处理的自己,又由于这是一颗满二叉树,所以它相当于每次处理一条链,链与链之间的不影响,所以可以定义表示点在链中映射的结点编号,然后只需要开到80就够了(恐怕这就是这个题目唯一有价值的地方了吧)
最后是激动人心的上代码过程
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
#define rg register
const int _=40100;
inline int read()
{
rg char ch='!';rg int z=1,num=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')z=-1,ch=getchar();
while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
return z*num;
}
int n,a[_],b[_],c[_];
struct ed{int to,next;}e[_<<1];
vector<int>g[_];
int cnt,head[_];
inline void link(int u,int v){e[++cnt]=(ed){v,head[u]};head[u]=cnt;}
int sz[_],dep[_],dfn[_];
ll f[105][45][45];
void dfs(int u,int k)
{
dfn[u]=k;
sz[u]=1;
for(rg int i=head[u];i;i=e[i].next)
{
rg int v=e[i].to;
dep[v]=dep[u]+1;
g[u].push_back(v);
if(g[u][1])dfs(v,k+2);
else dfs(v,k+1);
sz[u]+=sz[v];
}
if(sz[u]==1)
for(rg int i=0;i<=dep[u];++i)
for(rg int j=0;j<=dep[u];++j)
f[dfn[u]][i][j]=1ll*c[u]*(a[u]+i)*(b[u]+j);
else
for(int i=0;i<=dep[u];++i)
for(int j=0;j<=dep[u];++j)
f[dfn[u]][i][j]=min(f[dfn[g[u][0]]][i][j]+f[dfn[g[u][1]]][i][j+1],f[dfn[g[u][0]]][i+1][j]+f[dfn[g[u][1]]][i][j]);
}
int main()
{
memset(f,63,sizeof(f));
n=read();
for(rg int x,y,i=1;i<n;++i)
{
x=read(),y=read();
if(y<0)link(i,-y+n-1);
else link(i,y);
if(x<0)link(i,-x+n-1);
else link(i,x);
}
for(rg int i=n;i<=2*n-1;++i)a[i]=read(),b[i]=read(),c[i]=read();
dep[1]=0;dfs(1,0);
printf("%lld\n",f[dfn[1]][0][0]);
return 0;
}