当前位置: 首页 > news >正文

题解:AT_abc311_h [ABC311Ex] Many Illumination Plans

题意:给出一棵树,每个节点有权值,重量和颜色,问对于每个子树 \(u\),选出一个包含 \(u\) 的虚树,满足重量之和 \(\le X\),相邻两个点颜色不同且权值和最大。

做法:

首先我们会一个非常平凡的 \(O(nX^2)\) 做法,但是这样怎么找都需要一个没有任何性质的 \((max,+)\) 卷积,显然很完蛋,我们考虑为什么会这么慢,因为我们需要枚举节点重量的一个线性组合,所以导致会多个加入,这样很爆炸。

我们不妨先考虑一个更基础的问题,P2014。这个题的题意就是选节点必须选父亲,那么我们考虑这样一个 dp。\(dp_{i,j}\) 代表子树 \(i\),里面选了 \(j\) 个节点,但是这样不够,没有优化空间,我们考虑在做 dp 的时候将 dp 值直接传给儿子,再对自己进行贡献。但是为了保证父亲也选了,我们强制限定向下传的时候 \(1\rightarrow i\) 路径上的若干个点都必选,前面的贡献算过了,在下传的时候加上儿子的权即可,细节可以看代码。

考虑这样做的正确性,因为如果我们进入一个子树,我们就立刻算掉了贡献保证一定有,而保证了这样之后其实元素间就没有什么其他限制了。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 305;
int dp[maxn][maxn], val[maxn], n, m, dep[maxn];
vector<int> e[maxn];
void dfs(int u) {for (int i = 0; i < e[u].size(); i++) {int v = e[u][i]; dep[v] = dep[u] + 1;for (int j = dep[u] + 1; j <= m; j++)dp[v][j] = dp[u][j - 1] + val[v];dfs(v);for (int j = dep[u] + 1; j <= m; j++)dp[u][j] = max(dp[u][j], dp[v][j]);}
}
signed main() {cin >> n >> m; m++;for (int x, i = 1; i <= n; i++)cin >> x >> val[i], e[x].push_back(i);dep[0] = 1;dfs(0);cout << dp[0][m] << endl;return 0;
}

然后我们考虑对这个题也施加这个 trick,那么先考虑暴力怎么做,\(dp_{u,0/1,i}\) 代表 \(u\) 子树内最上层的颜色为 \(0/1\),重量为 \(i\),最大的权值之和。如果没有颜色直接秒了,考虑有颜色怎么办。

我们如果直接下传,那么会出现一个问题,可能我们会在子树 \(v\) 中从 \(dp_{u,0}\) 转移来一个 \(1\) 颜色的点,\(w\) 子树中又有一个 \(0\) 颜色的,这样就出问题了。

这里有一步天才的想法,我们直接下传 \(dp_{v,0} = dp_{v,1}=dp_{u,0}\),再下传 \(dp_{v,0} = dp_{v,1}=dp_{u,1}\),然后前者只取 \(dp_{v,0}\),后者只取 \(dp_{v,1}\),分讨一下下面的情况发现确实是可以覆盖所有情况的!

但是问题来了,这样的复杂度是 \(\sum 2^{dep}\) 的,那么既然是深度相关,那么完全可以用重链剖分优化一下,启发式一下,直接继承重儿子然后再对于其他的考虑。

分析复杂度,\(T(n) = T(a_1)+2\sum T(a_i)+O(X)\),那么我们应该让后面的 \(\times 2\) 的部分尽量大,那么就让子树间平均,那么就是 \(T(n) = (2k-1)T(\frac{n}{k})+O(X)\),由主定理得到复杂度为 \(O(n^{\log_{k}2k-1}X)\)\(k=2\) 时取到最大,为 \(O(n^{1.59}X)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 205, inf = 9e18; 
int n, x, p[maxn], v[maxn], w[maxn], c[maxn], sz[maxn], son[maxn];
vector<int> e[maxn];
void dfs1(int u, int fa) {sz[u] = 1;for (int i = 0; i < e[u].size(); i++) {int v = e[u][i];dfs1(v, u), sz[u] += sz[v];if(sz[son[u]] < sz[v])son[u] = v;}	
}
int ans[maxn];
pair<vector<int>, vector<int> > dfs(int u, vector<int> dp, bool use) {if(use) {for (int i = 0; i < e[u].size(); i++) {int v = e[u][i];if(v == son[u])continue;dfs(v, dp, use);}}vector<int> f[2];if(son[u]) {pair<vector<int>, vector<int> > p = dfs(son[u], dp, use);f[0] = p.first, f[1] = p.second;for (int i = 0; i < e[u].size(); i++) {int v = e[u][i];if(v == son[u])continue;f[0] = dfs(v, f[0], 0).first;f[1] = dfs(v, f[1], 0).second;}}elsef[0] = f[1] = dp;if(use) {for (int i = x; i >= w[u]; i--) ans[u] = max(ans[u], f[c[u] ^ 1][i - w[u]] + v[u]);}for (int i = x; i >= w[u]; i--) f[c[u]][i] = max(f[c[u]][i], f[c[u] ^ 1][i - w[u]] + v[u]);return make_pair(f[0], f[1]);
}
signed main() {cin >> n >> x;for (int i = 2; i <= n; i++)cin >> p[i], e[p[i]].push_back(i);dfs1(1, 0);for (int i = 1; i <= n; i++)cin >> v[i] >> w[i] >> c[i];vector<int> v; v.resize(x + 1);for (int i = 1; i <= x; i++)v[i] = -inf;dfs(1, v, 1);for (int i = 1; i <= n; i++)cout << ans[i] << endl;return 0;
}
http://www.sczhlp.com/news/151736/

相关文章:

  • 手机上怎么创建wordpress网站关键词排名优化工具
  • 美团外卖网站开发wordpress添加时间轴
  • 企业网站seo运营网络设计报告网络安全
  • dedecms 网站标题 设置吉林长春seo网站建设网站优化
  • 网站怎么做自己站长兰州网站制作公司
  • 怎么做轴承网站网站评论回复如何做
  • 做网站一般用什么 语言专业的手机网站建设公司排名
  • 网站形式创意设计椅子
  • 七台河做网站做论坛网站需要多少钱
  • 网站正能量免费推广软件搜资源
  • 商丘市做1企业网站的公司铜仁北京网站建设
  • php+网站开发+pdf自动写作文网站
  • 网站工信部本案网络营销专业是学什么的
  • 建立网站用英语怎么说申请网站做自己的产品
  • 河南省网站建设软件开发者英文
  • 实时热点新闻事件2021上海知名seo公司
  • 用模板做网站教程忻府网站建设
  • 绍兴建设网站广州网站建设企业
  • python网站开发实例教程WordPress菜单过滤器
  • 来个黑黑的网站wordpress上传word
  • 男男做暧暧视频网站网站建设及网页设计
  • 净水 技术支持 东莞网站建设wordpress 筛选 文章
  • 怎么样创办一个网站推荐国外网站设计
  • 电子元器件网站怎么做东莞营销商城网站建设
  • Beatty 定理
  • 潍坊高级网站建设推广做网站的团队
  • 做网站跳转百度做公司网站有用吗
  • 奎屯网站建设搜素引擎排名优化计费方式
  • 制作logo免费网站太原住房和城乡建设部网站
  • php的网站架构建设框架wordpress 修改登录