jzoj5336 【NOIP2017提高A组模拟8.24】提米树 (dfs序dp,奇异姿势dp)
来源:互联网 发布:大学 知乎 编辑:程序博客网 时间:2024/06/05 00:18
题面
分析
剪枝的意思就是你可以任意选点作为叶子。(前提是他子树不选)
比赛的时候有一种60分的n^2 log n做法,就是在dfs序上直接dp.
但是正解比较奇怪,先画颗树出来看看,就会发现根到真·叶子的路径上有且只有一个被选为叶子。于是我们考虑设一种玄学的dp。 令
想想能更新i的点有哪些。 由于要保证每条到叶子的路径上都有选中的,那么当前状态要么没有意义( 选他的祖先 ),要么就从相邻的叶子节点到二者lca (不含)这条路径上的点更新过来。 (看不懂的就看图吧)
这样每次枚举两个相邻叶子,然后暴力枚举从哪个绿点转移的话是O(n^2)的。
没有被转移到的点价值就是本身。 (因为他不需要接盘,只选自己就行)
在优化之前,先证明一个结论: 相邻叶子节点的路径长度(也就是点数-1)不会超过2n.
考虑一条边会被选到多少次,当然最多两次了,子树外到内 与 内到外各一次。子树内都选不到他。
这样从上到下更新要更新的点,lca~当前要更新的点 的路径mx当然是递增的,然后左边决策集合中的mx也是递增的,维护一个指针now表示当前决策集合(按深度排序,感受一下) 1..now-1是用自己那边的mx,然后now..lca是用 lca~当前要更新的点上的mx。
这样维护一个前缀和+后缀和,快速计算一下两部分的最优值就可以O(n)做了。 (细节比较多但为什么有大佬能打进1000byte)
Demo
#include <cstdio>#include <iostream>#include <cstring>#define max(a,b) ((a)<(b)?(b):(a))#define min(a,b) ((a)<(b)?(a):(b))using namespace std;const int N=1e5+10,INF=2e9;int final[N],nex[N],to[N],tot,dep[N];int n,a[N];int fa[N],ch[N];int f[N];int s[N],td[N],pre[N],sufmxa[N],sufmxf[N];int tmp[N];void link(int x,int y) {to[++tot]=y, nex[tot]=final[x], final[x]=tot;}void dfs(int x) { dep[x]=dep[fa[x]]+1; if (!final[x]) ch[++ch[0]]=x; else for (int i=final[x]; i; i=nex[i]) fa[to[i]]=x, dfs(to[i]);}int init(int x,int y) { int tx=x,ty=y,g=0; s[0]=td[0]=0; while (dep[ty]>dep[x]) td[++td[0]]=ty,ty=fa[ty]; while (dep[tx]>dep[y]) { if (f[tx]==f[0]) f[tx]=a[tx]; s[++s[0]]=tx; tx=fa[tx]; } while (tx!=ty) { if (f[tx]==f[0]) f[tx]=a[tx]; td[++td[0]]=ty, s[++s[0]]=tx; tx=fa[tx],ty=fa[ty]; } s[++s[0]]=g=tx; pre[0]=sufmxa[s[0]]=sufmxf[s[0]]=-INF; if (f[g]==f[0]) f[g]=a[g]; for (int i=s[0]-1; i; i--) { sufmxf[i]=max(sufmxf[i+1],f[s[i]]); //max f[a..g] sufmxa[i]=max(sufmxa[i+1],a[s[i+1]]);//max a[fa[a]..g] } for (int i=1; i<s[0]; i++) pre[i]=max(pre[i-1],f[s[i]] - sufmxa[i]); //max ans[1..i] return g;}int main() { freopen("3.in","r",stdin);// freopen("3.out","w",stdout); cin>>n; for (int i=1; i<=n; i++) { int k=0; scanf("%d %d",&a[i],&tmp[0]); for (int j=1; j<=tmp[0]; j++) scanf("%d",&tmp[j]); for (int j=tmp[0]; j; j--) link(i,tmp[j]); } memset(f,128,sizeof f); dfs(1); for (int i=1; i<ch[0]; i++) { int x=ch[i],y=ch[i+1],g=init(x,y),now=s[0],rmx=0; for (int d,j=td[0]; j; j--) { d=td[j], rmx=max(rmx,a[fa[d]]); while (now>1 && sufmxa[now-1]<=rmx) now--; f[d]=max(pre[now-1], sufmxf[now] - rmx)+a[d]; } } int ans=0; for (int i=ch[ch[0]]; i; i=fa[i]) { if (f[i]==f[0]) f[i]=a[i]; ans=max(ans,f[i]); } printf("%d\n",ans);}
阅读全文
0 0
- jzoj5336 【NOIP2017提高A组模拟8.24】提米树 (dfs序dp,奇异姿势dp)
- 【JZOJ5336】【NOIP2017提高模拟】提米树(DP、前缀和)
- 【JZOJ5336】【NOIP2017提高A组模拟8.24】提米树
- JZOJ5377. 【NOIP2017提高A组模拟9.19】开拓 DP
- jzoj5290 【NOIP2017提高组A组模拟8.17】行程的交集 (树上路径交,dfs序+树状数组维护姿势)
- 【NOIP2017提高A组模拟8.24】提米树
- 【JZOJ5335】【NOIP2017提高组模拟】早苗(DP、矩阵乘法)
- 【NOIP2017提高A组集训10.25】凤凰院凶真(dp)
- 5332. 【NOIP2017提高A组模拟8.23】密码 AC自动机+数位DP
- JZOJ5347【NOIP2017提高A组模拟9.5】遥远的金字塔 斜率优化 DP
- JZOJ5351. 【NOIP2017提高A组模拟9.7】简单无向图 DP+组合数学
- 【NOIP2017提高A组模拟9.7】简单无向图 dp
- JZOJ5379. 【NOIP2017提高A组模拟9.21】Victor爱数字 数位DP
- JZOJ5393【NOIP2017提高A组模拟10.5】Snake vs Block DP
- JZOJ5400. 【NOIP2017提高A组模拟10.7】Repulsed 树型DP+贪心
- 【NOIP2017提高A组模拟8.24】早苗
- 空【NOIP2017提高A组模拟8.24】
- JZOJ5408. 【NOIP2017提高A组集训10.21】Dark DP
- hdu6170(dp)
- spring cloud教程---Eureka
- pl sql
- angular2中ViewChild,索引值相关
- Spring Boot : CROS解决跨域问题(七)
- jzoj5336 【NOIP2017提高A组模拟8.24】提米树 (dfs序dp,奇异姿势dp)
- C语言 输入
- url带加号+,get时显示空格
- Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法与解析
- Java中的throw和throws的区别
- 《C++程序设计教程》——初识STL
- Android 事件分发(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)
- 1054. 求平均值 (20) 字符串处理
- 观察者模式--消息服务