博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[2019.2.28]BZOJ4033 [HAOI2015]树上染色
阅读量:6465 次
发布时间:2019-06-23

本文共 1309 字,大约阅读时间需要 4 分钟。

首先我们设\(dp_{i,j}\)表示\(i\)和的子树中,有\(j\)个黑色节点的最大边权和。

我们设\(i\)当前已合并的子树大小为\(sz_i\)

现在我们要合并节点\(x\)和它的子节点\(y\)

我们考虑\(x\)\(y\)之间的边对答案的贡献。

这个贡献就是这条边[(一侧的黑点数\(\times\)另一侧的黑点数)+(一侧的白点数\(\times\)另一侧的白点数)]\(\times\)边权。

为什么呢?

显然对于任意位于这条边两侧的同色点,它们之间的路径必然经过这条边。

我们设这次合并之前的\(dp_x\)\(ldp\),这条边边权为\(ev\),那么有

\(dp_{x,i}=max\{dp_{y,j}+ldp_{i-j}+j\times(k-j)\times ev+(sz_y-j)\times(n-k-sz_y+j)\times ev\}\)

但是这样看起来单次合并是\(O(n^2)\)的,总时间复杂度就是\(O(n^3)\)的。

一开始我也是这么认为的。

一交发现过了,而且跑的很快。

它实际上似乎是\(O(n^2)\)的。

为什么呢?

树形dp复杂度太玄学了

code:

#include
#define Add(l,r,val) (c[l]+=val,c[r+1]-=val)#define Sum(l,r) (sum[r]-(l?sum[l-1]:0))using namespace std;struct edge{ int t,v,nxt;}e[4010];int n,k,u,v,w,cnt,be[2010],sz[2010];long long dp[2010][2010],cpy[2010],ans;void add(int x,int y,int val){ e[++cnt].t=y,e[cnt].v=val,e[cnt].nxt=be[x],be[x]=cnt;}void Merge(int x,int y,int ev){ for(int i=0;i<=k;++i)cpy[i]=dp[x][i],dp[x][i]=0; for(int i=0;i<=k&&i<=sz[y];++i)for(int j=0;i+j<=k&&j<=sz[x];++j)dp[x][i+j]=max(dp[x][i+j],dp[y][i]+cpy[j]+1ll*ev*i*(k-i)+1ll*ev*(sz[y]-i)*(n-k-sz[y]+i));}void TDP(int x){ sz[x]=1; for(int i=be[x];i;i=e[i].nxt)!sz[e[i].t]?TDP(e[i].t),Merge(x,e[i].t,e[i].v),sz[x]+=sz[e[i].t],0:0;}int main(){ scanf("%d%d",&n,&k); for(int i=1;i

转载于:https://www.cnblogs.com/xryjr233/p/BZOJ4033.html

你可能感兴趣的文章
Android Studio 2.0 preview3 BUG
查看>>
兼容几乎所有浏览器的透明背景效果
查看>>
Go语言4
查看>>
jeesite 框架搭建与配置
查看>>
Adb移植(一)简单分析
查看>>
Linux VNC server的安装及简单配置使用
查看>>
阿里宣布开源Weex ,亿级应用匠心打造跨平台移动开发工具
查看>>
Android项目——实现时间线程源码
查看>>
招商银行信用卡重要通知:消费提醒服务调整,300元以下消费不再逐笔发送短信...
查看>>
python全栈_002_Python3基础语法
查看>>
C#_delegate - 调用列表
查看>>
交换机二层接口access、trunk、hybird三种模式对VLAN的处理过程
查看>>
jQuery.extend 函数详解
查看>>
[转]Windows的批处理脚本
查看>>
lnmp高人笔记
查看>>
[转载] OpenCV2.4.3 CheatSheet学习(三)
查看>>
子程序框架
查看>>
多维数组元素的地址
查看>>
数据库运维体系_SZMSD
查看>>
福大软工1816 · 第三次作业 - 结对项目1
查看>>