[树形依赖多重背包] BZOJ 4910 [Sdoi2017] 苹果树
来源:互联网 发布:软件架构怎么设计 编辑:程序博客网 时间:2024/05/16 05:55
首先解决依赖背包
如果是0/1背包,按照后序遍历dp,根据选或不选决策
现在是多重背包,那么这个点只留一个,剩下的变成一个新点挂上去,这样仍然满足依赖关系,
转移的时候多重背包用单调对列优化
可以发现如果除了最长的一条链,剩余最多
因为权值为正 那么最长链必然连到叶子,剩余必然取
那么我们枚举叶子 然后两边总共取出
两边需要两次儿子顺序不同的后序遍历
复杂度被卡常,我把部分分特判了才过TAT
#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>#include<cstring>#define cl(x) memset(x,0,sizeof(x))#define pb push_backusing namespace std;typedef long long ll;inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int N=40005;const int KK=500005;const int NK=51000000;struct edge{ int u,v,next;}G[N<<1];int head[N],inum;inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;}int a[N],v[N];#define V G[p].vint n,K;int ncnt,pos[N];int lst1[N],lst2[N],pnt;int pre1[N],pre2[N],back1[N],back2[N];int size[N];int f1[NK],f2[NK];int leaf[N];int val[N],depth[N];inline void dfs1(int u){ pre1[u]=pnt+1; size[u]=1; for (int p=head[u];p;p=G[p].next){ val[V]=val[u]+v[V],depth[V]=depth[u]+1; dfs1(V); size[u]+=size[V]; } lst1[++pnt]=u; back1[u]=pnt;}inline void dfs2(int u){ pre2[u]=pnt+1; vector<int> v; for (int p=head[u];p;p=G[p].next) v.pb(V); for (int i=v.size()-1;~i;i--) dfs2(v[i]); lst2[++pnt]=u; back2[u]=pnt;}int Q[KK],l,r;int Q2[KK];#define F(i,j) (ff[(i)*(K+1)+(j)])inline int max(int a,int b){ return a>b?a:b;}inline void DP(int *ff,int *lst,int *pre){ F(0,0)=0; for (int k=1;k<=K;k++) F(0,k)=-1<<29; for (int i=1;i<=ncnt;i++){ int x=lst[i]; int *f=ff+i*(K+1),*g=ff+(i-1)*(K+1),*t=ff+(pre[x]-1)*(K+1); //for (int k=0;k<=K;k++) f[k]=t[k]; memcpy(f,t,sizeof(int)*(K+1)); if (a[x]==0) continue; if (a[x]==1){ for (int k=1;k<=K;k++) f[k]=max(f[k],g[k-1]+v[x]); }else{ l=r=-1; Q[++r]=0; Q2[r]=g[Q[r]]-Q[r]*v[x]; for (int j=1;j<=K;j++){ while (l<r && Q[l+1]<j-a[x]) l++; if (l<r) f[j]=max(f[j],Q2[l+1]+j*v[x]); int tmp=g[j]-j*v[x]; while (l<r && tmp>=Q2[r]) r--; Q[++r]=j; Q2[r]=tmp; } } }}namespace Work{ inline bool cmp(int x,int y){ return v[x]>v[y]; } int idx[N]; inline void Solve(){ for (int i=1;i<=n;i++) idx[i]=i,a[i]+=a[pos[i]]; a[1]--; int x=K+1,ans=v[1]; sort(idx+1,idx+n+1,cmp); for (int i=1;i<=n;i++){ int t=min(x,a[idx[i]]); x-=t; ans+=v[idx[i]]*t; if (!x) break; } printf("%d\n",ans); }}int main(){ int T; int x,y,z; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(T); while (T--){ read(n); read(K); ll tot=0; ncnt=n; int maxv=0; for (int i=1;i<=n;i++){ read(x); read(y); read(z); tot+=y; maxv=max(maxv,x); if (x) add(x,i,++inum),leaf[x]=1; v[i]=z; a[i]=1; if (y>1) pos[i]=++ncnt,v[ncnt]=z,a[ncnt]=y-1,add(i,ncnt,++inum); } if (maxv<=1){ Work::Solve(); cl(head); inum=0; cl(leaf); cl(pos); continue; } pnt=0; val[1]=v[1]; depth[1]=1; dfs1(1); DP(f1,lst1,pre1); pnt=0; dfs2(1); DP(f2,lst2,pre2); int ans=-1<<30; for (int i=1;i<=n;i++) if (!leaf[i]){ int *f=f1+(K+1)*(pre1[i]+size[i]-2); int *g=f2+(K+1)*(pre2[i]-1); int x=min(tot-depth[i],(ll)K); for (int k=0;k<=x;k++) ans=max(ans,val[i]+f[k]+g[x-k]); } printf("%d\n",ans); cl(head); inum=0; cl(leaf); cl(pos); } return 0;}
阅读全文
0 0
- [树形依赖多重背包] BZOJ 4910 [Sdoi2017] 苹果树
- [树上依赖多重背包 DP] BZOJ 4910 [Sdoi2017]苹果树
- [树上依赖背包] BZOJ4910 LOJ2268: [SDOI2017] 苹果树
- BZOJ 2427 软件安装 (tarjan 树形依赖背包)
- 树形依赖背包
- Hdu1011 树形dp,多重背包
- [caioj 1114]多叉苹果树---树形dp+01背包
- bzoj 1017: [JSOI2008]魔兽地图DotR (树形DP+多重背包)
- hdu1561树形dp+依赖背包
- 动态规划--树形依赖背包
- 二叉苹果树 树形DP
- 【树形dp】二叉苹果树
- BZOJ 1531 POI2005 Bank notes 多重背包
- BZOJ 1531: [POI2005]Bank notes 多重背包
- hdu 3593 树形依赖背包的优化
- hdu1561有依赖的背包-树形dp
- (树形dp 依赖背包)hdu1561
- CTSC 97 选课 ----树形依赖背包
- 安装g2o时显示找不到libcholmod-dev怎么办
- Ubuntu清理系统垃圾 命令
- C语言编程规范
- arcgis api for js入门开发系列十二地图打印(GP服务)
- EF之Code First设置主外键关系(二)
- [树形依赖多重背包] BZOJ 4910 [Sdoi2017] 苹果树
- linux守护进程介绍以及如何编写守护进程
- 获取 Android 模拟器root 权限(解决data权限问题)
- redis 主从复制过程
- 观察者模式-百度摇号短信提醒举例说明
- Python3简单教程(五)函数
- 简单的平面几何问题
- df -vh 出现的问题
- 第4章 CMD 与 ENTRYPOINT 的区别