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/ 看了这么多树链剖分的解释,几个小时后总算把树链剖分弄懂了. 树链剖分的功能:快速修改,查询树上 ...
随机推荐
- 设计模式C++学习笔记之十(Builder建造者模式)
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.一段晦涩难懂的文字,实现创建不同表示的方法就是给创建的过程传入创建的参数.详细的还是看代码吧. 10.1.解释 ...
- 【转】C++对成员访问运算符->的重载
运算符->的重载比较特别,它只能是非静态的成员函数形式,而且没有参数. 1.如果返回值是一个原始指针,那么就将运算符的右操作数当作这个原始指针所指向类型的成员进行访问: 2.如果返回值是另一个类 ...
- strstr()函数的使用
strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串.如果是,则该函数返回str2在str1中首次出现的地址:否则,返回NULL. 实例: /** *Descriptio ...
- 流形学习(manifold learning)综述
原文地址:https://blog.csdn.net/dllian/article/details/7472916 假设数据是均匀采样于一个高维欧氏空间中的低维流形,流形学习就是从高维采样数据中恢复低 ...
- Docker部署tomcat及应用
前提Docker已安装完成. 由于测试网无法直接连入互联网,所以在本机虚拟机内下载tomcat镜像并传到测试网主机中. 虚拟机内执行 查找tomcat镜像: # docker search tomca ...
- css3 翻转
参考资料: WEB骇客 : http://www.webhek.com/css-flip/ Demo : Demo(谷歌浏览器观看,没做兼容) Demo截图: 代码: <!DOCTYPE h ...
- CF 189A Cut Ribbon
#include<bits/stdc++.h> using namespace std; const int maxn = 4000 + 131; int n, a, b, c; int ...
- Linux系统下安装pycharm
在 linux下打开浏览器,搜索pycharm,点击download. 下载好的文件的名称可能是 ‘pycharm-professional-2018.3.5.tar.gz’. 打开终端界面,输入命令 ...
- 前端-----margin用法(盒子模型里补充)
margin塌陷问题 当时说到了盒模型,盒模型包含着margin,为什么要在这里说margin呢?因为元素和元素在垂直方向上margin里面有坑. 我们来看一个例子: html结构: <div ...
- JS中的进制转换
1 前言 js的进制转换, 分为2进制,8进制,10进制,16进制之间的相互转换, 我们直接利用 对象.toString()即可实现. 仅作为记录. 2 代码 //10进制转为16进制 (10).to ...