sdoi2017苹果树
题解:
非常奇妙的一题。。
没有免费操作我都不会$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苹果树的更多相关文章
- [SDOI2017]苹果树
题目描述 https://www.luogu.org/problemnew/show/P3780 题解 一道思路巧妙的背包题. 对于那个奇怪的限制,我们对此稍加分析就可以发现它最后选择的区域是一个包含 ...
- BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...
- BZOJ4910 : [Sdoi2017] 苹果树
问题等价于树形依赖背包,允许一条链每个点各免费一次. 设$f[i][j]$表示按DFS序考虑到$i$,体积为$j$的最大收益. 先放入不能免费的物品,等遍历完儿子后再放入必选的物品,那么$i$到根路径 ...
- 【做题】SDOI2017苹果树——dfs序的运用
原文链接 https://www.cnblogs.com/cly-none/p/9845046.html 题意:给出一棵\(n\)个结点的树,在第\(i\)个结点上有\(a_i\)个权值为\(v_i\ ...
- hs-black 杂题选讲
[POI2011]OKR-Periodicity 考虑递归地构造,设 \(\text{solve(s)}\) 表示字典序最小的,\(\text{border}\) 集合和 \(S\) 的 \(\tex ...
- DP 优化小技巧
收录一些比较冷门的 DP 优化方法. 1. 树上依赖性背包 树上依赖性背包形如在树上选出若干个物品做背包问题,满足这些物品连通.由于 01 背包,多重背包和完全背包均可以在 \(\mathcal{O} ...
- 【LOJ】#2268. 「SDOI2017」苹果树
题解 显然权值都是正的,我们最深的那个点一定延伸到了某个叶子 我们抛去这条链之外再选K个点即可 如果直接对一棵树选K个点,满足这样的依赖关系,可以通过一个后序遍历的顺序做出来 转移方法是 \(dp[i ...
- SDOI2017 Round2 详细题解
这套题实在是太神仙了..做了我好久...好多题都是去搜题解才会的 TAT. 剩的那道题先咕着,如果省选没有退役就来填吧. 「SDOI2017」龙与地下城 题意 丢 \(Y\) 次骰子,骰子有 \(X\ ...
- codevs 1228 苹果树 树链剖分讲解
题目:codevs 1228 苹果树 链接:http://codevs.cn/problem/1228/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
随机推荐
- Apollo 启动脚本解析
Apollo 启动脚本解析 sudo service docker start -- 是在ubuntu14.04中打开 在dev_start.sh脚本中会调用restart_map_volume.sh ...
- lvs为何不能完全替代DNS轮询
1)接入层架构要考虑的问题域为:高可用.扩展性.反向代理+扩展均衡 2)nginx.keepalived.lvs.f5可以很好的解决高可用.扩展性.反向代理+扩展均衡的问题 3)水平扩展scale o ...
- 制作ecc证书(linux命令行)
生成ECC证书.Debian:/home/test# openssl ecparam -out EccCA.key -name prime256v1 -genkeyDebian:/home/test# ...
- CANopen--实现双电机速度同步
图1 将上图图中左边的电机和右边的电机进行速度同步,右边的电机同步左边的电机速度.这里需要知道Copley的驱动中的速度环的输入输出情况.如下图所示,速度环限制器接收速度命令信号,经限制后,产生一限制 ...
- android SDK与ADT版本更新问题
android SDK与ADT版本更新问题 问题:This Android SDK requires Android Developer Toolkit version 14.0.0 or above ...
- CF D. One-Dimensional Battle Ships
一个set水 + 区间判断个数问题.... #include<iostream> #include<cstdio> #include<cstring> #inclu ...
- Apache 和 Tomcat联系和区别
作者:郭无心链接:https://www.zhihu.com/question/37155807/answer/72706896来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- Python-WEB -VUE初识
走进Vue_渐进式 JavaScript 框架 通过对框架的了解与运用程度,来决定其在整个项目中的应用范围,最终可以独立以框架方式完成整个web前端项目 what -- 什么是Vue 可以独立完成前后 ...
- 洛谷P4117 [Ynoi2018]五彩斑斓的世界 [分块,并查集]
洛谷 Codeforces 又是一道卡常题-- 思路 YNOI当然要分块啦. 分块之后怎么办? 零散块暴力,整块怎么办? 显然不能暴力改/查询所有的.考虑把相同值的用并查集连在一起,这样修改时就只需要 ...
- bat命令查询硬件信息
bat命令查询硬件信息 50 需求是这样的写一个bat命令,当命令执行的时候,先请用户输入姓名,然后继续执行查询出以下信息并写入一个文件,文件名称随便,文件可以放在与当前命令同一个文件夹下.最终文件中 ...