HDU 6268 Master of Subgraph (2017 CCPC 杭州 E题,树分治 + 树上背包)
题目链接 2017 CCPC Hangzhou Problem E
题意 给定一棵树,每个点有一个权值,现在我们可以选一些连通的点,并且把这点选出来的点的权值相加,得到一个和。
求$[1, m]$里面哪些值可以被表示成选出来的点的权值和。用$01$序列的方式输出。
重现赛赛场上的我英勇无畏,大胆做$3000$次FFT合并两个bitset表示的答案。
然后TLE到结束(活该)
其实这个题确实要用bitset,关键是能不能把合并两个bitset转化成合并一个数和一个bitset。
考虑点分治。我们先选出树的重心,然后考虑一定要选这个点的答案。
然后这道题的关键来了。
假设我选择了某个点,那么我必须选择这个点的父亲。
现在开始递归这棵树。每次递归到一个点,这个点的bitset初值化为父亲结点表示的bitset右移$w[x]$位。
他的意义是,当前这个点如果选了,那么他的父亲必选,那也就是求他父亲当前求得的答案集合结合这个点的权值的答案。
然后回溯的时候,父亲表示的bitset要或上儿子表示的bitset。
这是因为在后面这个父亲的其他儿子求解的之后,要用到这个父亲已经求得的信息,并结合起来,
通过这个父亲起到连接的效果。
最后以当前这个分治中心为根的树的答案就是分治中心表示的bitset。
那么接下来继续往下递归求解就可以了。
时间复杂度$O(nlogn \cdot \frac{m}{w})$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 3e3 + 10;
const int M = 1e5 + 10; int T;
int n, m;
int et;
int f[N], w[N], sz[N], vis[N];
int root, sum;
int cnt;
vector <int> v[N];
bitset <M> b[N], ans; void getroot(int x, int fa){
sz[x] = 1;
f[x] = 0; for (auto u : v[x]){
if (u == fa || vis[u]) continue;
getroot(u, x);
sz[x] += sz[u];
f[x] = max(f[x], sz[u]);
} f[x] = max(f[x], sum - sz[x]);
if (f[x] < f[root]) root = x;
} void calc(int x, int fa, int now){
cnt ^= 1;
b[cnt] = b[cnt ^ 1];
b[cnt] |= (b[cnt ^ 1] << now);
for (auto u : v[x]){
if (vis[u] || u == fa) continue;
calc(u, x, w[u]);
}
} void dp(int x, int fa){
b[x] = b[fa] << w[x];
for (auto u : v[x]){
if (vis[u] || u == fa) continue;
dp(u, x);
b[x] |= b[u];
}
} void calcsize(int x, int fa){
sz[x] = 1;
b[x].reset();
for (auto u : v[x]){
if (vis[u] || u == fa) continue;
calcsize(u, x);
sz[x] += sz[u];
}
} void solve(int x){
++et;
vis[x] = 1; b[0].reset();
b[0].set(0);
calcsize(x, 0);
dp(x, 0);
ans |= b[x]; for (auto u : v[x]){
if (vis[u]) continue;
sum = sz[u];
f[0] = n + 1;
getroot(u, root = 0);
solve(root);
}
} int main(){ scanf("%d", &T);
while (T--){
ans.reset();
scanf("%d%d", &n, &m);
rep(i, 0, n + 1) v[i].clear(); et = 0;
rep(i, 2, n){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
} rep(i, 1, n) scanf("%d", w + i); memset(vis, 0, sizeof vis);
f[0] = n + 1;
sum = n;
getroot(1, root = 0);
solve(root); rep(i, 1, m) if (ans[i]) putchar(49);
else putchar(48);
putchar(10);
} return 0;
}
HDU 6268 Master of Subgraph (2017 CCPC 杭州 E题,树分治 + 树上背包)的更多相关文章
- HDU 6271 Master of Connected Component(2017 CCPC 杭州 H题,树分块 + 并查集的撤销)
题目链接 2017 CCPC Hangzhou Problem H 思路:对树进行分块.把第一棵树分成$\sqrt{n}$块,第二棵树也分成$\sqrt{n}$块. 分块的时候满足每个块是一个 ...
- hdu 6268 Master of Subgraph(点分治+bitset)
You are given a tree with n nodes. The weight of the i-th node is wi. Given a positive integer m, no ...
- 2017 ccpc哈尔滨 A题 Palindrome
2017 ccpc哈尔滨 A题 Palindrome 题意: 给一个串\(T\),计算存在多少子串S满足\(S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)\) 思路: 很明显这里的回文串长 ...
- HDU 6270 Marriage (2017 CCPC 杭州赛区 G题,生成函数 + 容斥 + 分治NTT)
题目链接 2017 CCPC Hangzhou Problem G 题意描述很清晰. 考虑每个家庭有且仅有$k$对近亲的方案数: $C(a, k) * C(b, k) * k!$ 那么如果在第$1$ ...
- 2017 CCPC杭州 题解
2017CCPC杭州题目PDF Problem A. Super-palindrome 题解: 给你一个字符串,每一步可以将一个字符替换为另一个字符,问你最少多少步可以使得,该字符串任意奇数子串为回文 ...
- 算法学习分析-点分治 HDU 6269 Master of Subgraph
首先给出定义 点分治是一种处理树上路径的工具 挂出一道题目来:Master of Subgraph 这道题目让你求所有联通子图加和所能产生数字,问你1到m之间,那些数字可以被产生 这道题目,假如我们利 ...
- 2017 CCPC 杭州 流水账
day0: 队内训练ccpc 秦皇岛,敝校自己出的题,感觉一个星期没怎么写代码,手生得很,不出意料被打飞了. day1 (热身赛): 热身赛还算顺利,A题看有的队几分钟就草过去了,还以为又是西安ICP ...
- 2017 CCPC 杭州 HDU6273J 区间修改(线段树&差分数组)
http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf 解析 线段树区间延迟更新 或 差分数组 两个数 统计2和3的最少的 ...
- 2017 CCPC 杭州 HDU6265B 积性函数
题目链接 http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf B题 数论题 h(n)=∑ d|n φ(d) × ...
随机推荐
- USACO Section2.2 Party Lamps 解题报告 【icedream61】
lamps解题报告------------------------------------------------------------------------------------------- ...
- 小程序使用Canvas画饼图
先上效果图 -------------------------------------------------------------wxml代码开始------------------------- ...
- Python代码书写规范
Python 编码规范 一 代码编排1 缩进.4个空格的缩进(编辑器都可以完成此功能),不要使用Tap,更不能混合使用Tap和空格.2 每行最大长度79,换行可以使用反斜杠,最好使用圆括号.换行点要在 ...
- css3实现圆角边框渐变
<button class="border">112233</button> 创建button .border{ position: relative; b ...
- Python基础简介与简单使用
Python介绍 Python发展史 1989年,为了打发圣诞节假期,Guido开始写Python语言的编译器.Python这个名字,来自Guido所挚爱的电视剧Monty Python’s Flyi ...
- [译]14-spring 集合元素的注入
前面的文章已经介绍了如何往bean里面注入原始类型和引用类型.我们使用bean元素的contructor-arg或property子 元素的value属性注入java原始类型;同理,我们可以使用bea ...
- springbootDay03 cookie和session 购物车技术
一.会话技术 1. 什么是会话 在计算机术语中,会话指的是客户端和服务器交互通讯的过程.简单的理解,大家可以看成是两个普通的人在打电话.一次电话从通话开始到挂断,可以看成是会话. 会话的特征 会话能够 ...
- Actiivity 生命周期
Actiivity 生命周期,如下图所示: onCreate onStart (onRestarted) onResume onPaused(to onResume(User navigates to ...
- atan与atan2的区别
相比较ATan,ATan2究竟有什么不同?本篇介绍一下ATan2的用法及使用条件. 对于tan(θ) = y / x: θ = ATan(y / x)求出的θ取值范围是[-PI/2, PI/2]. θ ...
- 实用JS系列——事件类型
事件就是用户对窗口上各种组件的操作.JS中的事件中的事件即由访问Web页面的用户引起的一系列的操作.一般用于浏览器和用户操作进行交互,例如:用户的单击事件等. 类型分为: 内联模型.脚本模型和DOM2 ...