题解:

非常奇妙的一题。。

没有免费操作我都不会$nk$。。。。考试打个暴力就可以走人了

树上有依赖背包问题的正确做法是(为啥我之前学的不是这样的啊)

按照后续遍历做背包

做到一个点的时候 枚举它选不选 不选只能从子树外转移 选的话可以从x-1转移

而不是对每个点求一次$f[i][j]$ 这样是$n*k^2$

前者不管是多重背包还是0/1背包 复杂度都是$nk$的(单调队列优化)

将题目给的条件转化,变成有一条链是免费

我们会发现这样求出的路径是它到根的路径的左边和自己子树的背包

那么我们可以想到 如果按照右左根再遍历一遍 可以得到右边+自己子树的背包

另外有一个性质就是,这条链一定会到叶子

而我们发现对于叶子两个背包合并的话就只多算了当前点并且当前点到根这一段都没有算(只要把一个编号右移一位就没有重复了)

这恰好符合了题目的免费操作

但是注意那些点ai是可以>1也就是说还需要考虑付费部分

一种直观的思路是对其中一种dfs子儿子之前先把$(ai-1,vi)$作为一种物品放进去

其实这等价于再加一个$(ai-1,vi)$的儿子

然后这样就可以卡着空间过了。。 因为多加了儿子,数组需要2.5e7*2*2

***常数巨大但洛谷评测机快就过了

单调队列里面一堆变量写错。。

数组大小一堆开错。。然后查错查了一个小时。。

代码:

#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for(int i=h;i<=t;i++)
#define dep(i,t,h) for(int i=t;i>=h;i--)
#define ll long long
#define me(x) memset(x,0,sizeof(x))
#define mep(x,y) memcpy(x,y,sizeof(y))
#define mid (t<=0?(h+t-1)/2:(h+t)/2)
namespace IO{
char ss[<<],*A=ss,*B=ss;
IL char gc()
{
return A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++;
}
template<class T> void read(T &x)
{
rint f=,c; while (c=gc(),c<||c>) if (c=='-') f=-; x=(c^);
while (c=gc(),c>&&c<) x=(x<<)+(x<<)+(c^); x*=f;
}
char sr[<<],z[]; int Z,C1=-;
template<class T>void wer(T x)
{
if (x<) sr[++C1]='-',x=-x;
while (z[++Z]=x%+,x/=);
while (sr[++C1]=z[Z],--Z);
}
IL void wer1()
{
sr[++C1]=' ';
}
IL void wer2()
{
sr[++C1]='\n';
}
template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
template<class T>IL void mina(T &x,T y) {if (x>y) x=y;}
template<class T>IL T MAX(T x,T y){return x>y?x:y;}
template<class T>IL T MIN(T x,T y){return x<y?x:y;}
};
using namespace IO;
const int N=6e5;
const int N2=;
int n,k,ans[N],a[N],v[N],dp1[N2],dp2[N2],sum[N],cnt;
int dfn1[N],dfn2[N];
vector<int> ve[N];
struct re{
int a,b;
}p[N];
void dfs1(int x)
{
sum[x]=;
for (int i=;i<ve[x].size();i++)
{
ans[ve[x][i]]=ans[x]+v[x];
dfs1(ve[x][i]);
sum[x]+=sum[ve[x][i]];
}
dfn1[x]=++cnt;
int n1=dfn1[x]-,k1=n1*(k+);
int k2=dfn1[x]*(k+);
int h=,t=; p[]=(re){,};
rep(i,,k)
{
if (h<=t&&(i-p[h].a)>a[x]) h++;
if (h<=t) dp1[k2+i]=v[x]*i+p[h].b;
int now=dp1[k1+i]-v[x]*i;
while (h<=t&&now>=p[h].b) t--;
p[++t]=(re){i,now};
}
n1=dfn1[x]-sum[x],k1=n1*(k+);
rep(i,,k)
{
dp1[k2+i]=MAX(dp1[k2+i],dp1[k1+i]);
if (i) maxa(dp1[k2+i],dp1[k2+i-]);
}
}
bool vis[N];
void dfs2(int x)
{
vis[x]=;
sum[x]=;
for (int i=(int)(ve[x].size())-;i>=;i--)
{
dfs2(ve[x][i]);
sum[x]+=sum[ve[x][i]];
}
dfn2[x]=++cnt;
int n1=dfn2[x]-,k1=n1*(k+);
int k2=dfn2[x]*(k+);
int h=,t=; p[]=(re){,};
rep(i,,k)
{
if (h<=t&&(i-p[h].a)>a[x]) h++;
if (h<=t) dp2[k2+i]=v[x]*i+p[h].b;
int now=dp2[k1+i]-v[x]*i;
while (h<=t&&now>=p[h].b) t--;
p[++t]=(re){i,now};
}
n1=dfn2[x]-sum[x],k1=n1*(k+);
rep(i,,k)
{
dp2[k2+i]=MAX(dp2[k2+i],dp2[k1+i]);
if (i) maxa(dp2[k2+i],dp2[k2+i-]);
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int T;
read(T);
rep(ttt,,T)
{
read(n); read(k); me(dp1); me(dp2);
rep(i,,N-)
{
vector<int> v2;
v2.swap(ve[i]);
}
rep(i,,n)
{
int x; read(x);
read(a[i]); read(v[i]);
if (x) ve[x].push_back(i);
a[i+n]=a[i]-,v[i+n]=v[i];
a[i]=;
ve[i].push_back(i+n);
}
cnt=; dfs1();
cnt=; dfs2();
int num=;
rep(i,n+,*n)
rep(j,,k)
maxa(num,ans[i]+dp1[dfn1[i]*(k+)+j]
+dp2[(dfn2[i]-)*(k+)+k-j]);
cout<<num<<endl;
}
return ;
}

sdoi2017苹果树的更多相关文章

  1. [SDOI2017]苹果树

    题目描述 https://www.luogu.org/problemnew/show/P3780 题解 一道思路巧妙的背包题. 对于那个奇怪的限制,我们对此稍加分析就可以发现它最后选择的区域是一个包含 ...

  2. BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)

    BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...

  3. BZOJ4910 : [Sdoi2017] 苹果树

    问题等价于树形依赖背包,允许一条链每个点各免费一次. 设$f[i][j]$表示按DFS序考虑到$i$,体积为$j$的最大收益. 先放入不能免费的物品,等遍历完儿子后再放入必选的物品,那么$i$到根路径 ...

  4. 【做题】SDOI2017苹果树——dfs序的运用

    原文链接 https://www.cnblogs.com/cly-none/p/9845046.html 题意:给出一棵\(n\)个结点的树,在第\(i\)个结点上有\(a_i\)个权值为\(v_i\ ...

  5. hs-black 杂题选讲

    [POI2011]OKR-Periodicity 考虑递归地构造,设 \(\text{solve(s)}\) 表示字典序最小的,\(\text{border}\) 集合和 \(S\) 的 \(\tex ...

  6. DP 优化小技巧

    收录一些比较冷门的 DP 优化方法. 1. 树上依赖性背包 树上依赖性背包形如在树上选出若干个物品做背包问题,满足这些物品连通.由于 01 背包,多重背包和完全背包均可以在 \(\mathcal{O} ...

  7. 【LOJ】#2268. 「SDOI2017」苹果树

    题解 显然权值都是正的,我们最深的那个点一定延伸到了某个叶子 我们抛去这条链之外再选K个点即可 如果直接对一棵树选K个点,满足这样的依赖关系,可以通过一个后序遍历的顺序做出来 转移方法是 \(dp[i ...

  8. SDOI2017 Round2 详细题解

    这套题实在是太神仙了..做了我好久...好多题都是去搜题解才会的 TAT. 剩的那道题先咕着,如果省选没有退役就来填吧. 「SDOI2017」龙与地下城 题意 丢 \(Y\) 次骰子,骰子有 \(X\ ...

  9. codevs 1228 苹果树 树链剖分讲解

    题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...

随机推荐

  1. python3+selenium入门14-上传下载文件

    上传文件一种方式是通过定位input标签,然后使用send_keys()方法传入需要上传文件的路径.另一种是使用第三方插件去上传文件.下面看下imput标签的方式.工具可以自己查下. <!DOC ...

  2. 028_shell脚本递归求值

    一. #!/bin/sh factorial() { if [ "$1" -gt "1" ]; then i=`expr $1 - 1` j=`factoria ...

  3. 更新ocr voting后第二个节点启动不起来

    [+ASM2]@qdcx-db2[/home/grid]$crsctl check crs CRS-4638: Oracle High Availability Services is online ...

  4. unit test

    1) State vs Behaviour Verificationhttps://manas.tech/blog/2009/04/30/state-vs-behaviour-verification ...

  5. POJ 2115

    ax=b (mod n) 该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0 令d=gcd(a,n) 有该方程的 最小整数解为 x = e (mod n/d) 其中e ...

  6. JS 手机端多张图片上传

    代码如下 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="u ...

  7. Go语言中的byte和rune区别、对比

    Go语言中byte和rune实质上就是uint8和int32类型.byte用来强调数据是raw data,而不是数字:而rune用来表示Unicode的code point.参考规范: uint8 t ...

  8. jemter 新增sha256函数

    1  https://blog.csdn.net/y100100/article/details/80701049 2  https://blog.csdn.net/y100100/article/d ...

  9. Confluence 6 数据收集隐私策略

    为什么 Confluence 收集使用数据? 针对 Confluence 我们很自豪 Confluence 是这个星球上最高效和强大的协作工具,我们也计划继续保持这个特性,尽我们最大的努力提供更新的 ...

  10. MYSQL查询系列 常考问题

    表结构: `student`('id'.'name'.'code'.'age'.'sex')学生表 `teacher`('id'.'name')教师表 `course`('id'.'name'.'te ...