zoukankan      html  css  js  c++  java
  • [BZOJ4182]Shopping

    题目

      点这里看题目。
       BZOJ 上这还是权限题。

    分析

      不难发现,最后我们走过的点一定组成了树上的一个连通块。
      如何枚举树上一个连通块?我们可以想到用点分治。由于每一次我们进行分治之后会进行子树继续分治,这就相当于将原图变成了几个连通块。我们只需要对于每次分治,将分治中心设定为 “ 必选 ” ,然后用某种方法计算这个连通块的所有连通子块的最优贡献即可。
      不难发现每个商店的物品可以拿出来做多重背包。因此我们发现可以用树形依赖的多重背包计算贡献。设状态:
      (f(u,j)):$u$的子树中,花$j$的代价可以获得的最大收益。
      发现存在连通块每个点上都必须买东西的限制,因此我们必须在每个点上,先强制买一个东西之后,再进行多重背包的计算。这相当于总共可用的钱变少了。之后继续搜索,将子树上的答案合并上来。
      由于本题对时间的限制不强,因此可以写多重背包二进制优化。妄图掩盖单调队列写挂的事实。

    代码

    #include <cstdio>
    
    const int INF = 0x3f3f3f3f;
    const int MAXN = 505, MAXM = 4005, MAXD = 105;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
    	return a < b ? a : b;
    }
    
    struct edge
    {
    	int to, nxt;
    }Graph[MAXN << 1];
    
    int f[MAXN][MAXM];
    int deq[MAXM];
    int siz[MAXN], mx[MAXN];
    int head[MAXN], w[MAXN], c[MAXN], d[MAXN];
    int N, M, cnt, ans;
    bool vis[MAXN];
    
    void upt( int &x, const int v ) { x = MAX( x, v ); }
    bool visible( const int u, const int fa ) { return u ^ fa && ! vis[u]; }
    int getVal( const int u, const int x ) { return f[u][x] - ( x / c[u] ) * w[u]; }
    
    void init()
    {
    	ans = cnt = 0;
    	for( int i = 1 ; i <= N ; i ++ ) siz[i] = mx[i] = vis[i] = head[i] = 0;
    	for( int i = 1 ; i <= N ; i ++ )
    		for( int j = 0 ; j <= M ; j ++ )
    			f[i][j] = -INF;
    }
    
    void addEdge( const int from, const int to )
    {
    	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    
    void resize( const int u, const int fa )
    {
    	siz[u] = 1, mx[u] = 0;
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    		if( visible( v = Graph[i].to, fa ) )
    			resize( v, u ), siz[u] += siz[v], mx[u] = MAX( mx[u], siz[v] );
    }
    
    int getCen( const int u, const int fa, const int all )
    {
    	if( MAX( mx[u], all - siz[u] ) <= all / 2 ) return u;
    	for( int i = head[u], v, tmp ; i ; i = Graph[i].nxt )
    		if( visible( v = Graph[i].to, fa ) )
    			if( tmp = getCen( v, u, all ) ) return tmp;
    	return 0;
    }
    
    void DFS( const int u, const int fa, int lim )
    {
    	if( lim < c[u] ) return ;
    	lim -= c[u];
    	int D = d[u] - 1, C = c[u], W = w[u];
    	for( int i = 0 ; i <= lim ; i ++ ) f[u][i] = f[fa][i] + W;
    	for( int i = 0, cur ; ( 1 << i ) <= D ; i ++ )
    	{
    		cur = 1 << i;
    		for( int j = lim ; j >= C * cur ; j -- ) upt( f[u][j], f[u][j - C * cur] + W * cur );
    		D -= cur;
    	}
    	if( D ) for( int j = lim ; j >= C * D ; j -- ) upt( f[u][j], f[u][j - D * C] + W * D );
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    		if( visible( v = Graph[i].to, fa ) )
    		{
    			DFS( v, u, lim );
    			for( int j = c[v] ; j <= lim ; j ++ )
    				upt( f[u][j], f[v][j - c[v]] );
    		}
    }
    
    void cal( const int u )
    {
    	DFS( u, 0, M );
    	for( int i = 0 ; i <= M - c[u] ; i ++ ) upt( ans, f[u][i] );
    }
    
    void divide( const int u )
    {
    	resize( u, 0 ); 
    	int tmp = getCen( u, 0, siz[u] );
    	cal( tmp ), vis[tmp] = true;
    	for( int i = head[tmp], v ; i ; i = Graph[i].nxt )
    		if( ! vis[v = Graph[i].to] )
    			divide( v );
    	vis[tmp] = false;
    }
    
    int main()
    {
    	int T;
    	read( T );
    	while( T -- )
    	{
    		read( N ), read( M ); init();
    		for( int i = 1 ; i <= N ; i ++ ) read( w[i] );
    		for( int i = 1 ; i <= N ; i ++ ) read( c[i] );
    		for( int i = 1 ; i <= N ; i ++ ) read( d[i] );
    		for( int i = 1, a, b ; i < N ; i ++ )
    			read( a ), read( b ), addEdge( a, b ), addEdge( b, a );
    		divide( 1 );
    		write( ans ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    day30---内置函数
    day30---绑定方法与非绑定方法
    元类以及属性查找
    python 内置方法/魔法方法
    python 面向对象高级-反射机制
    centos7下jenkins升级
    屏蔽百度右侧热搜
    centos7部署汉化版gitlab
    CentOS 7 安装 Jenkins
    centos7安装与配置ansible
  • 原文地址:https://www.cnblogs.com/crashed/p/12583865.html
Copyright © 2011-2022 走看看