OpenJudge1043 树上游戏(换根dp+细节处理)
树上游戏
给定一棵 nnn 个节点的树,点从 111 到 nnn 编号,点有点权,边有边权, Alice\text{Alice}Alice 和 Bob\text{Bob}Bob 两人在做游戏。
棋子以某一个点 sss 为起点,玩家移动该棋子,有以下两条规则:
由 Alice\text{Alice}Alice 开始,轮流移动棋子,最终的得分为经过的点权之和减去经过的边权之和。
Alice\text{Alice}Alice 想要最大化得分, Bob\text{Bob}Bob 想要最小化得分,假设两人都采取最优策略,那么最终得分是多少呢?
- Alice\text{Alice}Alice需要让结果尽可能大:fu,0=maxv∈sonu(fv,1+valu−wi)f_{u,0}=\max_{v\in \text{son}_u}(f_{v,1}+\text{val}_u-w_i)fu,0=maxv∈sonu(fv,1+valu−wi)
- Bob\text{Bob}Bob需要让结果尽可能小:fu,1=minv∈sonu(fv,0+valu−wi)f_{u,1}=\min_{v\in \text{son}_u}(f_{v,0}+\text{val}_u-w_i)fu,1=minv∈sonu(fv,0+valu−wi)
由于存在换根操作,不难发现只要记录fu,0f_{u,0}fu,0的最大次大值以及fu,1f_{u,1}fu,1的最小次小值即可从父节点更新子节点实现换根操作。
还有在第一遍dfs时不能以入度为1的点为根进行dfs,因为这个点在其他点为根的时是叶子节点,某些信息会错误更新比如下面数据
5
2147483647 2147483647 2147483647 2147483647 -2147483647
1 2 2147483647
2 3 2147483647
3 4 2147483647
4 5 2147483647
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long;
constexpr int N=100010;
constexpr ll INF=0x3f3f3f3f3f3f3f3f;
int h[N],e[2*N],ne[2*N],w[2*N],idx;
void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;}
int val[N],n;
ll f[N][2],g[N][2],ans[N];// f[u][0/1]表示u子树 该A/B移动
int fr[N][2];
int d[N];
bool leaf[N];
void update(int u,int k,int v,ll x)// 更新 最大次大/最小次小
{if(k==0){if(x>f[u][k]) {g[u][k]=f[u][k];f[u][k]=x;fr[u][k]=v;}else if(x>g[u][k]) g[u][k]=x;}else{if(x<f[u][k]){g[u][k]=f[u][k];f[u][k]=x;fr[u][k]=v;}else if(x<g[u][k]) g[u][k]=x;}
}
void dfs1(int u,int fa)
{leaf[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;leaf[u]=0;dfs1(v,u);for(int k=0;k<=1;k++)update(u,k,v,f[v][k^1]+val[u]-w[i]);}if(leaf[u]) f[u][0]=f[u][1]=val[u];//叶子节点初值
}
void dfs2(int u,int fa)
{ans[u]=f[u][0];for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;for(int k=0;k<=1;k++){if(leaf[v])//叶子节点特殊处理{if(fr[u][k]==v) f[v][k^1]=g[u][k]+val[v]-w[i];else f[v][k^1]=f[u][k]+val[v]-w[i];}else//换根{if(fr[u][k]==v) update(v,k^1,u,g[u][k]+val[v]-w[i]);elseupdate(v,k^1,u,f[u][k]+val[v]-w[i]);}}dfs2(v,u);}
}
int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n;memset(h,-1,sizeof h);for(int i=1;i<=n;i++) cin>>val[i];for(int i=1;i<=n;i++) f[i][0]=g[i][0]=-INF,f[i][1]=g[i][1]=INF;for(int i=1;i<n;i++){int a,b,c;cin>>a>>b>>c;add(a,b,c),add(b,a,c);d[a]++,d[b]++;}int rt=1;while(d[rt]==1) rt++;//找一个度数不为1的为根dfs1(rt,0);dfs2(rt,0);for(int i=1;i<=n;i++) cout<<ans[i]<<'\n';
}
OpenJudge1043 树上游戏(换根dp+细节处理)相关推荐
- 树形dp ---- 树形换根dp F - The Maximum Subtree
题目链接 题目大意: 给定一颗树,求这个树的最大子树,且这个子树是一个good-tree. good-tree的定义是:每个节点可以表示成一个数值区间,而树上的边表示两个点表示的数值区间相交 解题思路 ...
- BZOJ 2159 「国家集训队」Crash 的文明世界(第二类斯特林数,换根DP)【BZOJ计划】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2159 是 hydro 的 BZOJ ...
- 2019长沙学院新生赛(A水,B水,C(整除分块),D水,E(巧数学),F(二分+bfs),H(换根dp),I(线段树)J(dp+倍增+lca))
A-XOR SUM 通过简单观察得知连续四个数的异或值就是等于0,暴力找出左区间和右区间就可以了,最多跑四个单位 0^1^2^3==0 4^5^6^7=0 #include<bits/std ...
- 2020牛客多校第一场B虚树+质数筛+换根dp
题目大意: 1.可以发现阶乘增长是很快的所以你要把整颗树建立出来是不实际的. 2.我们可以假设这棵树已经建出来出来了我们应该怎么搞 首先很明显是一个树形dp, 我们设dp[j],是以j为u到其他点距离 ...
- 洛谷 - P4323 [JSOI2016]独特的树叶(树上哈希+换根dp)
题目链接:点击查看 题目大意:给出一棵 n 个节点的树 A ,再给出一棵 n + 1 个节点的树 B,题目保证了树 B 是树 A 添加了一个叶子结点后的一棵树,只不过编号的顺序不同,现在问这个叶子节点 ...
- 牛客多校1 - Infinite Tree(虚树+换根dp+树状数组)
题目链接:点击查看 题目大意:给出一个无穷个节点的树,对于每个大于 1 的点 i 来说,可以向点 i / minvid[ i ] 连边,这里的 mindiv[ x ] 表示的是 x 的最小质因数,现在 ...
- 换根dp求树所有节点的最小深度
链接:https://ac.nowcoder.com/acm/contest/18072/A 牛妹有一张连通图,由n个点和n-1条边构成,也就是说这是一棵树,牛妹可以任意选择一个点为根,根的深度为0, ...
- [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...
- Accumulation Degree --- 换根dp
个人感觉,换根dp的实质就是在不确定答案是以哪个节点为根时,先假设1个节点为根去遍历,更新答案,接着利用数学公式推出该假设根的子儿子为根的时候对应的值. #include<iostream> ...
最新文章
- java彩色的世界_JAVA真彩色转256色的实现
- R语言实战学习笔记-高级数据管理
- python的常见矩阵除法_Numpy矩阵除法返回所有零
- Java ADF Template程序不能连接ArcGIS Server问题
- Jenkins+Ant自动布署war
- 微信公众号之生成带参数的二维码
- PROTEL技术大全
- Android开发视频教程,最全面的,总共200多集
- 电容单位F法拉、mF毫法、纳法nF、皮法pF之间是如何转换
- C盘根目录出现msdia80.dll解决办法
- 淘宝APP用户行为分析
- miflash刷机:fastboot模式/保留数据刷机
- 1082 射击比赛 (20分)
- 杭电oj2111(JAVA
- vue拖动滑块验证组件
- 黄金思维圈,看透问题本质的利器,成功者必备工具
- 解决container_linux.go:262: starting container process caused:
- 对比度受限直方图均衡化CLAHE算法原理及Opencv C++代码实现
- 史上最强Java八股文面试题,堪称2023最强!!!
- p8h61主板升级cpu_如何升级和安装新的CPU或主板(或两者)
热门文章
- 2010C语言添加背景图片_2019级C语言大作业 - 火柴人试炼之地
- mysql+误操作怎么恢复_MySQL 误操作后如何快速恢复数据
- jsp需要多少java基础_Java基础——JSP(一)
- 契税申报期限_税局正式公告!财产和行为税合并纳税申报!附税种申报要点
- mybatis mysql usegeneratedkeys_mybatis中useGeneratedKeys用法--插入数据库后获取主键值
- golang 切片 接口_Golang语言常用关键字之 make 和 new
- 数学中R,Z,N,Q都代表什么意思?
- C++实现链式基数排序
- 蓝桥杯2016初赛-生日蜡烛-枚举
- 并发协作模型“生产者/消费者模式“