zoukankan      html  css  js  c++  java
  • [HDU6268]Master of Subgraph

    [HDU6268]Master of Subgraph

    题目大意:

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

    思路:

    重心剖分。考虑处理当前处理出的以重心(x)为根的子树。首先求出当前子树的DFS序,设用(node[i])表示DFS序为(i)的结点编号。考虑动态规划,用(f[i][j])std::bitset<M> f[N])表示包含DFS序为(i)的结点,是否有权值和为(j)的连通子图。设当前结点为(x),枚举子结点(y_{1sim k}),则转移方程为(f[x]=(f[y_1]vee f[y_2]veeldotsvee 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{nmlog 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('
    ');
    		clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    maven 多环境打包
    velocity 将数字转为以万为单位,保留2位小数
    mybatic 结果为null,返回0
    websocket-spring 整合
    烂泥:rsync配置文件详解
    烂泥:【转】rsync命令参数详解
    烂泥:linux文件同步之rsync学习(一)
    烂泥:使用snmpwalk采集设备的OID信息
    烂泥:apache密码生成工具htpasswd的应用
    烂泥:apache性能测试工具ab的应用
  • 原文地址:https://www.cnblogs.com/skylee03/p/9098393.html
Copyright © 2011-2022 走看看