BZOJ4910 : [Sdoi2017] 苹果树

问题等价于树形依赖背包,允许一条链每个点各免费一次。

设$f[i][j]$表示按DFS序考虑到$i$,体积为$j$的最大收益。

先放入不能免费的物品,等遍历完儿子后再放入必选的物品,那么$i$到根路径上所有点都只算了不能免费的部分。

然后将DFS序翻转,设$h[i][j]$表示按DFS序考虑到$i$,体积为$j$的最大收益。

等遍历完儿子后再放入必选的物品和不能免费的物品,那么$i$到根路径上所有点都没有算。

如此一来,对于每个叶子$i$,用$f[i][j]+h[i][k-j]$更新答案即可。

对于不能免费的物品,需要用单调队列优化转移。

时间复杂度$O(nk)$。

#include<cstdio>
#include<cstring>
const int N=20010,M=25520010;
int Case,n,m,K,T,i,fa[N],a[N],b[N],g[N],nxt[N],ans,F[M],H[M];
inline void add(int x,int y){nxt[y]=g[x];g[x]=y;}
inline void up(int&a,int b){a<b?(a=b):0;}
inline void solve(int*f,int A,int B){
  int i,j=0,h=1,t=0;
  static int q[500010],p[500010];
  for(i=0;i<=m;i++,j+=B){
    f[i]-=j;
    while(h<=t&&f[q[t]]<f[i])t--;
    q[++t]=i;
    while(i-q[h]>A)h++;
    p[i]=f[q[h]]+j;
  }
  memcpy(f,p,T);
}
void dfsl(int x){
  int i,j,A=a[x],B=b[x];
  if(A)solve(F+x*K,A,B);
  for(i=g[x];i;i=nxt[i]){
    memcpy(F+i*K,F+x*K,T);
    dfsl(i);
    B=b[i];
    int*s=F+x*K+1,*e=F+i*K;
    for(j=1;j<=m;j++,s++,e++)up(*s,*e+B);
  }
}
void dfsr(int x,int y){
  int i,j,A=a[x],B=b[x];
  y+=B;
  for(i=g[x];i;i=nxt[i]){
    memcpy(H+i*K,H+x*K,T);
    dfsr(i,y);
    B=b[i];
    int*s=H+x*K+1,*e=H+i*K;
    for(j=1;j<=m;j++,s++,e++)up(*s,*e+B);
  }
  if(!g[x]){
    int*s=H+x*K+m,*e=F+x*K;
    for(j=0;j<=m;j++,s--,e++)up(ans,*s+*e+y);
  }
  if(A)solve(H+x*K,A,b[x]);
}
int main(){
  scanf("%d",&Case);
  while(Case--){
    scanf("%d%d",&n,&m);
    K=m+1;T=K*sizeof(int);
    for(i=1;i<=n;i++)g[i]=0;
    for(i=1;i<=n;i++){
      scanf("%d%d%d",&fa[i],&a[i],&b[i]);a[i]--;
      if(fa[i])add(fa[i],i);
    }
    memset(F+K,0,T);
    memset(H+K,0,T);
    dfsl(1);
    for(i=1;i<=n;i++)g[i]=0;
    for(i=n;i;i--)if(fa[i])add(fa[i],i);
    ans=0;
    dfsr(1,0);
    printf("%d\n",ans);
  }
  return 0;
}

  

时间: 2024-10-13 10:35:18

BZOJ4910 : [Sdoi2017] 苹果树的相关文章

sdoi2017苹果树

题解: 没有免费操作我都不会$nk$.... 树上有依赖背包问题的正确做法是(为啥我之前学的不是这样的啊) 直接dfs下去维护背包 而不是对每个点求一次$f[i][j]$ 这样是$n*k^2$ 前者不管是多重背包还是0/1背包 复杂度都是$nk$的(单调队列优化) 然后考虑有一条链是免费的操作 原文地址:https://www.cnblogs.com/yinwuxiao/p/10057559.html

[SDOI2017]苹果树 题解

首先,观察题意,可以发现在最长链下再接一个点,结果一定更优. 也就是说,可以免费选一条最长链,之后正常选. 我们枚举选的最长链,然后算出剩下部分的最优解. 有4部分: 1.链上每个点都选一个. 2.链上剩下的部分. 3.链的左面. 4.链的右面. 1可以直接计算. 那么,我们需要先进行树形背包,然后再通过某方式将其余3个合并. 我们知道,在此问题中,合并2个背包是\(O(k)\)的: 但3个及以上则是\(O(k^2)\)的,无法承受. 所以,我们只能在计算中就把其中两个合并,这样就只需合并2个了

codevs——1228 苹果树

1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点

[Sdoi2017]新生舞会

[Sdoi2017]新生舞会 http://www.lydsy.com/JudgeOnline/problem.php?id=4819 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴.有n个男生和n个女生参加舞会 买一个男生和一个女生一起跳舞,互为舞伴.Cathy收集了这些同学之间的关系,比如两个人之前认识没计算

苹果树(线段树+Dfs序)

1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点上会结出一些苹果,但

[Codevs] 1228 苹果树

1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点上会结出一些苹果,但

AC日记——「SDOI2017」序列计数 LibreOJ 2002

「SDOI2017」序列计数 思路: 矩阵快速幂: 代码: #include <bits/stdc++.h> using namespace std; #define mod 20170408 #define ll long long struct MatrixType { int n,m; ll ai[105][105]; void mem(int n_,int m_) { n=n_,m=m_; for(int i=0;i<=n;i++) for(int v=0;v<=m;v++

Bzoj3757 苹果树

Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1978  Solved: 550 Description 神犇家门口种了一棵苹果树.苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条.由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色.我们用一个到n之间的正整数来表示一种颜色.树上一共有n个苹果.每个苹果都被编了号码,号码为一个1到n之间的正整数.我

二叉苹果树(树型DP+背包)

二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树: 2   5 \  / 3  4 \  / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 程序名:apple 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=