[HDU6268]Master of Subgraph

[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

时间: 2024-11-05 20:24:56

[HDU6268]Master of Subgraph的相关文章

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, now you need to judge that for every integer i in [1,m] whether there exists a connected subgraph which the sum of the weights of all nodes is equal to

HDU - 6268: Master of Subgraph (分治+bitset优化背包)

题意:T组样例,给次给出一个N节点的点权树,以及M,问连通块的点权和sum的情况,输出sum=1到M,用0或者1表示. 思路:背包,N^2,由于是无向的连通块,所以可以用分治优化到NlgN. 然后背包可以用bitset优化.注意不要想着背包合并背包,背包只能合并单点. #include<bits/stdc++.h> #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;i++) #define Gv G[u][i] #defin

点分治+动态点分治

最近好颓废,什么都学不进去... 感谢两篇:AKMer - 浅谈树分治  言简意赅 LadyLex - 点分治&动态点分治小结  讲解+例题,学到很多东西 点分治 动态点分治 ~ 点分治 ~ 经常遇见一类树上的计数题,问的是在某些条件下,选择一些点的方案数 若对于每个点的统计都需要遍历以其为根节点的子树,普通的做法就是$O(n^2)$的,在很多时候是不满足要求的 而这是点分治的专长 点分治是这样进行的: 1. 找到当前树的重心 2. 将重心及重心连出的边全部删去,那么就能将原来的树分割成森林 3

2017 CCPC杭州 题解

2017CCPC杭州题目PDF Problem A. Super-palindrome 题解: 给你一个字符串,每一步可以将一个字符替换为另一个字符,问你最少多少步可以使得,该字符串任意奇数子串为回文串,偶数子串为回文串. 满足上面条件一定是ababab这种形式,所以我们只要找到数量最多的两种字符用n-numa-numb得到ans1,有可能一种字符的数量过多,这时候我们只要把所有字符都变成这种字符就行了.得到n-numa,ans2; 在ans1和ans2中去最小值就是答案了: 参考代码: #in

ROS知识(20)----使用Master_API查询Master管理的节点话题服务内容

在一些应用中会需要获取master的uri地址,发布的话题,订阅的话题,发布的服务,节点的信息等等.这些功能我们通常可一通过rosnode list, rosnode info, rostopic list, rostopic info, rosservice list和 rosservice info 等命令查询,而这些功能是怎么做到的呢? 这就需要用到Master_API进行查询,ROS官方使用了python来实现(在ros_comm包中),这里我们使用c++来实现这些查询的功能. 1.实现

reset master和reset slave命令解析和区别

reset master删除所有index file 中记录的所有binlog 文件,将日志索引文件清空,创建一个新的日志文件,这个命令通常仅仅用于第一次用于搭建主从关系的时的主库, 注意: reset master 不同于purge binary log的两处地方1.reset master 将删除日志索引文件中记录的所有binlog文件,创建一个新的日志文件 起始值从000001 开始,然而purge binary log 命令并不会修改记录binlog的顺序的数值2.reset maste

kubernetes Master部署之Scheduler 以及 HA部署(5)

Kubernetes Scheduler作用是将Controller Manager将要新建的Pod按照特定的调度算法和调度策略绑定到集群中某个合适的Node上,并将绑定信息写入到etcd中. 一.部署Scheduler 下面生成kube-scheduler的kubeconfig文件,操作如下: cd /etc/kubernetes export KUBE_APISERVER="https://192.168.15.200:6443" 配置 cluster kubectl config

nis master的yppasswdd

yppasswdd是nis master特有的,用于和slave进行同步(即push的方式,包括yppasswd密码更新) 操作: master: # /usr/lib/yp/ypinit -m 所有从nis服务器 # service ypserv restart # service yppasswdd restart 有2个关键点: 1是ypinit -m 写上所有nis从服务器 2是需重启yppasswdd服务

2015南阳CCPC A - Secrete Master Plan 水题

D. Duff in Beach Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 无 Description Master Mind KongMing gave Fei Zhang a secrete master plan stashed in a pocket. The plan instructs how to deploy soldiers on the four corners of the city wall. Unfortunately, w