[BZOJ4182]Shopping 点分治+dfs序+多重背包单调队列
2018-01-04 22:05
471 查看
题目的限制就是买的点必须是一个联通块。
考虑先枚举一个点必选,那么就是一个有依赖的多重背包(就是选了子树根才能选子树中的点),用一下树型背包的套路:先搞出dfs序,设fi,j表示考虑了dfs序后i个点,花了j的钱的答案,如果不选就跳过整棵子树的区间,如果选就从i+1转移过来即可。
考虑把这个枚举变成点分治就可以了,复杂度O(mnlogn)。
代码:
考虑先枚举一个点必选,那么就是一个有依赖的多重背包(就是选了子树根才能选子树中的点),用一下树型背包的套路:先搞出dfs序,设fi,j表示考虑了dfs序后i个点,花了j的钱的答案,如果不选就跳过整棵子树的区间,如果选就从i+1转移过来即可。
考虑把这个枚举变成点分治就可以了,复杂度O(mnlogn)。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define fs first #define sc second using namespace std; int n,m,tim,w[510],c[510],d[510],sz[510],dfn[510],bg[510],ed[510],f[510][4010],ans; bool vis[510]; pair<int,int> dl[4010]; struct edge { int t; edge *n 10da0 ext; }*con[510]; void ins(int x,int y) { edge *p=new edge; p->t=y; p->next=con[x]; con[x]=p; } void getroot(int v,int fa,int size,int &rt) { bool flag=1; sz[v]=1; for(edge *p=con[v];p;p=p->next) if(!vis[p->t]&&p->t!=fa) { getroot(p->t,v,size,rt); sz[v]+=sz[p->t]; if(sz[p->t]*2>size) flag=0; } if(sz[v]*2<size) flag=0; if(flag) rt=v; } void dfs(int v,int fa) { dfn[++tim]=v;bg[v]=tim; for(edge *p=con[v];p;p=p->next) if(!vis[p->t]&&p->t!=fa) dfs(p->t,v); ed[v]=tim; } void solve(int v,int size) { int root; getroot(v,-1,size,root); vis[root]=1;tim=0; dfs(root,-1); memset(f[tim+1],0,sizeof(f[tim+1])); for(int i=tim,t=dfn[i];i;t=dfn[--i]) { for(int j=0;j<=m;j++) f[i][j]=f[ed[t]+1][j]; for(int cr=0;cr<c[t];cr++) for(int cd=0,hd=1,tl=0,j=cr;j<=m;j+=c[t],cd++) { for(;hd<=tl&&dl[hd].fs<cd-d[t];hd++); if(hd<=tl) f[i][j]=max(f[i][j],dl[hd].sc+cd*w[t]); for(;hd<=tl&&f[i+1][j]-cd*w[t]>=dl[tl].sc;tl--); dl[++tl]=make_pair(cd,f[i+1][j]-cd*w[t]); } } for(int i=0;i<=m;i++) ans=max(ans,f[1][i]); for(edge *p=con[root];p;p=p->next) if(!vis[p->t]) solve(p->t,sz[p->t]>sz[root]?size-sz[root]:sz[p->t]); } int main() { int ca; scanf("%d",&ca); while(ca--) { for(int i=1;i<=500;i++) con[i]=NULL; memset(vis,0,sizeof(vis));ans=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<=n;i++) scanf("%d",&d[i]); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y); ins(y,x); } solve(1,n); printf("%d\n",ans); } return 0; }
相关文章推荐
- [Bzoj4182]Shopping(点分治)(树上背包)(单调队列优化多重背包)
- BZOJ4182 shopping 点分治+多重背包单调队列优化
- bzoj4182 shopping [树形dp+点分治]
- 【BZOJ1758】【Wc2010】重建计划 分数规划+树分治单调队列check
- bzoj 1531: [POI2005]Bank notes 单调队列优化多重背包
- 【BZOJ】【P1758】【Wc2010】【重建计划】【题解】【点分治+二分+单调队列】
- BZOJ1758 [Wc2010]重建计划(二分答案+点分治+单调队列)
- 【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列
- bzoj 1758 [Wc2010]重建计划 01分数规划 点分治 单调队列
- 【BZOJ1758】重建计划,点分治+单调队列
- BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)
- bzoj 3219: 巡游 (点分治+单调队列+二分)
- BZOJ1758【点分治】【二分】【单调队列】
- BZOJ 1758 Wc2010 重建计划 树的点分治+二分+单调队列
- bzoj3219 巡游(二分答案+点分治+单调队列)
- 【bzoj1758】[Wc2010]重建计划 二分答案+单调队列+点分治
- bzoj 2500 幸福的道路 dfs 单调队列
- bzoj1296 [SCOI2009]粉刷匠 分组背包/单调队列优化
- wc2010 bzoj1758(点分治+二分+单调队列) TLE
- 【BZOJ1758】【WC2010】重建计划(点分治,单调队列)