zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    若没有特殊说明,博文密码都是我的生日
    「考前日志」11.18
    「考前日志」11.17
    洛谷 P2018 消息传递
    「考前日志」11.16
    「考前日志」11.15
    「考前日志」11.14
    2020.11.13 “考试”
    「考前日志」11.13
    AcWing277 饼干
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8857376.html
Copyright © 2011-2022 走看看