一些树上dp的复杂度证明
以下均为内网
树上染色 https://www.lydsy.com/JudgeOnline/problem.php?id=4033
可怜与超市 http://hzoj.com/contest/62/problem/5
可以简单的列出状态转移方程。
它的转移过程类似:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void dfs(int x)
2 {
3 for(unsigned i=0;i<p[x].size();++i) dfs(p[x][i]);
4 int cur=0;
5 memset(tmp[cur],0x3f,sizeof(tmp[cur]));
6 tmp[cur][0][0]=tmp[cur][1][0]=0;
7 for(unsigned i=0;i<p[x].size();++i)
8 {
9 int now=sz[p[x][i]]; cur^=1;
10 memset(tmp[cur],0x3f,sizeof(tmp[cur]));
11 for(int j=0;j<=sz[x];++j)
12 for(int k=0;k<=now;++k)
13 {
14 tmp[cur][1][k+j]=min(tmp[cur][1][k+j],tmp[cur^1][1][j]+dp[1][p[x][i]][k]);
15 tmp[cur][1][k+j]=min(tmp[cur][1][k+j],tmp[cur^1][1][j]+dp[0][p[x][i]][k]);
16 tmp[cur][0][k+j]=min(tmp[cur][0][k+j],tmp[cur^1][0][j]+dp[0][p[x][i]][k]);
17 }
18 sz[x]+=now;
19 }
20 ++sz[x];
21 dp[0][x][0]=0; dp[1][x][0]=0;
22 for(int i=1;i<=sz[x];++i) dp[1][x][i]=tmp[cur][1][i-1]+wc[x];//db(dp[1][x][i]);
23 for(int i=1;i<=sz[x];++i) dp[0][x][i]=min(tmp[cur][0][i],tmp[cur][0][i-1]+c[x]);
24 }
看上去的复杂度是$O(n^3)$,
然而仔细分析,复杂度只有$O(n^2)$,可以通过n为5000左右的数据。
引入一个概念,(a,b)为树上的点对,则该点对在图中有$n^2$个
观察状态的转移,
在x节点范围内,设x有k个节点,
复杂度为:
$\sum \limits_{i=1}^{k}\sum \limits_{j=i}^{k}size_i*size_j$
我们发现这样求出来,恰好是lca为x的点对个数。
每个点对一定存在且仅存在一个lca,每个点对只会被统计不超过一次,
所以总的复杂度为$O(n^2)$。