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

    bzoj

    description

    马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街。商店街有(n)个商店,并且它们之间的道路构成了一颗树的形状。
    (i)个商店只卖第(i)种物品,小苗对于这种物品的喜爱度是(w_i),物品的价格为(c_i),物品的库存是(d_i)。但是商店街有一项奇怪的规定:如果在商店(u,v)买了东西,并且有一个商店(w)(u)(v)的路径上,那么必须要在商店(w)买东西。小葱身上有(m)元钱,他想要尽量让小苗开心,所以他希望最大化小苗对买
    到物品的喜爱度之和。这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为OI选手的你,你能帮帮他吗?

    input

    输入第一行一个正整数(T),表示测试数据组数。
    对于每组数据,
    第一行两个正整数(n,m)
    第二行(n)个非负整数(w_1,w_2...w_n)
    第三行(n)个正整数(c_1,c_2...c_n)
    第四行(n)个正整数(d_1,d_2...d_n)
    接下来(n-1)行每行两个正整数(u,v)表示(u)(v)之间有一条道路

    output

    输出共(T) 行,每行一个整数,表示最大的喜爱度之和。

    sample input

    1
    3 2
    1 2 3
    1 1 1
    1 2 1
    1 2
    1 3
    

    sample output

    4
    

    hint

    $ n le 500,m le 4000,T le 5,W_i le 4000,D_i le 100$

    sol

    显然选出来的商店在树上要是一个连通块。
    枚举这个连通块的根,然后以这个点为根做树上依赖多重背包即可,如果多重背包用单调队列优化到(O(m))了的话复杂度就是(O(n^2m))
    注意单调队列优化多重背包的时候要把原先的(dp)值存下来,不然就重复转移了。
    树上依赖的问题可以先强制选某个点(u)至少一次,再加入子树答案,最后和不选(u)的答案取个(max)即可。

    然后会发现这里维护的就是子树信息,然后就(dsu on tree)一波,复杂度就变成了(O(nmlog n))
    当然点分治也是一样做的,复杂度也是(O(nmlog n))

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 505;
    const int M = 4005;
    const int inf = 1e9;
    int Case,n,m,w[N],c[N],d[N],to[N<<1],nxt[N<<1],head[N],cnt,q1[M],q2[M],hd,tl;
    int sz[N],son[N],f[N][M],g[N][M],ans;//g is backup
    void link(int u,int v){
    	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    void insert(int *dp,int x){
    	for (int i=m;i>=c[x];--i) dp[i]=dp[i-c[x]]+w[x];
    	for (int i=0;i<c[x];++i) dp[i]=-inf;
    	for (int i=0;i<c[x];++i){
    		hd=1,tl=0;
    		for (int j=i;j<=m;j+=c[x]){
    			while (hd<=tl&&(j-q1[hd])/c[x]>d[x]-1) ++hd;
    			while (hd<=tl&&dp[j]-j/c[x]*w[x]>=q2[tl]) --tl;
    			q1[++tl]=j;q2[tl]=dp[j]-j/c[x]*w[x];
    			dp[j]=q2[hd]+j/c[x]*w[x];
    		}
    	}
    }
    void upt(int u,int fa,int rt){
    	insert(f[rt],u);
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=fa){
    			for (int i=0;i<=m;++i) g[u][i]=f[rt][i];
    			upt(to[e],u,rt);
    			for (int i=0;i<=m;++i) f[rt][i]=max(f[rt][i],g[u][i]);
    		}
    }
    void dfs(int u,int fa){
    	sz[u]=1;son[u]=0;
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=fa){
    			dfs(to[e],u),sz[u]+=sz[to[e]];
    			if (sz[to[e]]>sz[son[u]]) son[u]=to[e];
    		}
    	for (int i=0;i<=m;++i) f[u][i]=max(f[son[u]][i],0);
    	insert(f[u],u);
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=fa&&to[e]!=son[u]){
    			for (int i=0;i<=m;++i) g[u][i]=f[u][i];
    			upt(to[e],u,u);
    			for (int i=0;i<=m;++i) f[u][i]=max(f[u][i],g[u][i]);
    		}
    }
    int main(){
    	Case=gi();
    	while (Case--){
    		memset(head,0,sizeof(head));cnt=0;
    		n=gi();m=gi();
    		for (int i=1;i<=n;++i) w[i]=gi();
    		for (int i=1;i<=n;++i) c[i]=gi();
    		for (int i=1;i<=n;++i) d[i]=gi();
    		for (int i=1;i<n;++i){
    			int u=gi(),v=gi();
    			link(u,v);link(v,u);
    		}
    		dfs(1,0);ans=0;
    		for (int i=1;i<=n;++i) ans=max(ans,f[i][m]);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    jsp转向
    什么是 XDoclet?
    tomcat中的几点配置说明
    mysql5问题
    POJ 3734 Blocks
    POJ 2409 Let it Bead
    HDU 1171 Big Event in HDU
    POJ 3046 Ant Counting
    HDU 2082 找单词
    POJ 1286 Necklace of Beads
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9307552.html
Copyright © 2011-2022 走看看