[HDU6268]Master of Subgraph

news/2024/11/17 7:36:37/

[HDU6268]Master of Subgraph

题目大意:

一棵\(n(n\le3000)\)个结点的树,每个结点的权值为\(w_i\)。给定\(m(m\le10^5)\),对于任意\(i\in[1,m]\),问书中是否有一个连通子图的权值和等于\(i\)

思路:

重心剖分。考虑处理当前处理出的以重心\(x\)为根的子树。首先求出当前子树的DFS序,设用\(node[i]\)表示DFS序为\(i\)的结点编号。考虑动态规划,用\(f[i][j]\)std::bitset<M> f[N])表示包含DFS序为\(i\)的结点,是否有权值和为\(j\)的连通子图。设当前结点为\(x\),枚举子结点\(y_{1\sim k}\),则转移方程为\(f[x]=(f[y_1]\vee f[y_2]\vee\ldots\vee f[y_k])<<w[x]\)

由于事实上对于每一个\(x\),我们并不需要知道\(f[x]\),而只需要利用它们求出\(f[root]\)的值,因此我们对于每一个\(x\)可以和上一个计算过的同级兄弟结点\(node[dfn[x]+sz[x]]\)合并。按DFS倒序枚举每一个结点\(x\),其DFS序为\(i\)。此时的状态转移方程为\(f[i]=(f[i+1]<<w[x])|f[i+sz[x]]\)。时间复杂度\(\mathcal O(\frac{nm\log n}\omega)\)

源代码:

#include<cstdio>
#include<cctype>
#include<bitset>
#include<forward_list>
inline int getint() {register char ch;while(!isdigit(ch=getchar()));register int x=ch^'0';while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');return x;
}
constexpr int N=3001,M=1e5+1;
bool vis[N];
std::forward_list<int> e[N];
std::bitset<M> ans,f[N];
int n,m,w[N],size[N],sz[N],node[N],dfn[N],root,whole,min;
inline void add_edge(const int &u,const int &v) {e[u].emplace_front(v);e[v].emplace_front(u);
}
inline void clear() {ans.reset();for(register int i=1;i<=n;i++) {vis[i]=false;e[i].clear();}
}
void dfs_root(const int &x,const int &par) {size[x]=1;int max=0;for(auto &y:e[x]) {if(y==par||vis[y]) continue;dfs_root(y,x);size[x]+=size[y];max=std::max(max,size[y]);}max=std::max(max,whole-size[x]);if(max<min) {min=max;root=x;}
}
inline void get_root(const int &x,const int &sum) {root=0;min=n+1;whole=sum;dfs_root(x,0);vis[root]=true;
}
void dfs(const int &x,const int &par) {sz[x]=1;dfn[x]=dfn[0]++;node[dfn[x]]=x;for(auto &y:e[x]) {if(y==par||vis[y]) continue;dfs(y,x);sz[x]+=sz[y];}
}
void solve(const int &x) {dfn[0]=0;dfs(x,0);f[dfn[0]]=1;for(register int i=dfn[0]-1;~i;i--) {const int &y=node[i];f[i]=(f[i+1]<<w[y])|f[i+sz[y]];}ans|=f[0];for(auto &y:e[x]) {if(vis[y]) continue;get_root(y,size[y]);solve(root);}
}
int main() {for(register int T=getint();T;T--) {n=getint(),m=getint();for(register int i=1;i<n;i++) {add_edge(getint(),getint());}for(register int i=1;i<=n;i++) {w[i]=getint();}get_root(1,n);solve(root);for(register int i=1;i<=m;i++) {printf("%d",(int)ans[i]);}putchar('\n');clear();}return 0;
}

转载于:https://www.cnblogs.com/skylee03/p/9098393.html


http://www.ppmy.cn/news/177071.html

相关文章

【力扣周赛#324】6266. 使用质因数之和替换后可以取到的最小值+6267. 添加边使所有节点度数都为偶数+6268. 查询树中环的长度

目录 6265. 统计相似字符串对的数目 - ac 6266. 使用质因数之和替换后可以取到的最小值 分解质因数 1、tle代码 2、优化ac代码 6267. 添加边使所有节点度数都为偶数 - 建图分类讨论 关于建图 6268. 查询树中环的长度 - LCA最近公共祖先 6265. 统计相似字符串对的数目…

LOJ6268拆分数

/*相当于每种物品都有无限个的背包毕竟考场上写exp是个比较危险的行为对数据进行根号分治是个比较好的方法对于小于等于根号的部分暴力背包转移 对于大于根号的 最多只会拿根号个 dp一下就好了*/ #include<cstdio> #include<algorithm> #include<cstring> #i…

UVALive - 6268 Cycling 贪心

UVALive - 6268 Cycling 题意&#xff1a;从一端走到另一端&#xff0c;有T个红绿灯&#xff0c;告诉你红绿灯的持续时间&#xff0c;求最短的到达终点的时间。x 思路&#xff1a; 转载于:https://www.cnblogs.com/macinchang/p/4753611.html

LOJ #6268. 分拆数

可以先将问题建模为 &#xff1a; 物品大小为1~inf 且每件物品数量无限 的背包选体积为1~n的方案数。 显然物品体积只有1~n有用&#xff0c;我们不妨把 体积1~sqrt(n) 的物品先暴力插入到背包中&#xff0c;设这一部分最后 体积i的方案数是 A[i] 。 考虑体积>sqrt(n)的物品怎…

[HDU6268]Master of Subgraph 树分治+bitset

bitset用法 bitset<B_Length> array[A_SIZE] 创建一个长度为B_Length,大小为A_SIZE的数组 bitset<B> a(n) 初始化一个值为n的bitset .reset() 将所有位初始化为0 .set() …

Hdu 6268 点分治 树上背包 bitset 优化

给你一颗大小为n(3000)的树,树上每个点有点权(100000),再给你一个数m(100000) i为1~m,问树中是否存在一个子图,使得权值为i. 每次solve到一个节点 用一个bitset维护所有经过它的链的取值(calc前要先初始化当前节点的bitset) 复杂度为nlognm/64 #include <bits/stdc.h> us…

HDU 6268 Master of Subgraph (2017CCPC杭州 E)分治+bitset优化

题目传送门 题意&#xff1a;给你一颗n(<3e3)个点的无向树&#xff0c;再给你一个数m(<1e5)&#xff0c;再给你n个点的权值a[i](<1e5) 求对于每个x属于[1,m]&#xff0c;是否存在一个连通子图的权值和正好为x。输出一个长度为m的01串&#xff0c;第i个位置上的数字表…

luogu P6268 [SHOI2002]舞会 [二分图最大独立集]

P6268 [SHOI2002]舞会 link 思路&#xff1a; 这题是一道二分图最大独立集的例题。 首先显然我们只用考虑两两跳过舞的男女&#xff0c; 剩下的就可以参加舞会。 考虑将跳过舞的两位人建一条无向边&#xff0c; 那一定是一张二分图。 那么求出有多少人不能参加舞会会比较简单。…