【HDU6662】Acesrc and Travel【树形DP】

题目大意:给你一棵树,每个节点有一个权值,Alice和Bob进行博弈,起点由Alice确定,确定后交替选择下一个点,Alice目标是最终值尽可能大,Bob目标是尽可能小
题解:很明显是树形DP,那么考虑如何dp
设F[i][0/1]表示第i个点先手选/后手选的答案
那么不难想到
F[i][0]=max(F[j][1])+v[i]
F[i][1]=min(F[j][0])+v[i]
一次以1为根进行dfs可以求出选择1为根时的答案,此时考虑换根
换根时将换根前的所有状态保存下来,dfs下去之后求出其子树答案后将状态复原
换根时有两种情况,1、原根的答案是新根推过来的。2、原根的答案不是从新根推过来的
对于第二种情况很简单,我们只需要把原根当做新根的子树然后进行转移即可
考虑第一种情况,将原根变为儿子之后,其F值由除新根之外的所有儿子转移而来
于是很容易想到在原有保存最大值(最小值)的基础上再保存次大值(次小值),这样就可以O(1)更新原根的答案了
更新完后就和第二种情况一样了
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define ll long long
#define INF 1e18
using namespace std;
int T,n;
ll v[],f[][];
ll mx[][],mn[][];
ll ans;
int mxbh[],mnbh[];
struct node
{
int x,y;
}tr[*];
int hd[],nxt[*],rn;
void build(int x,int y){tr[++rn]=(node){x,y};nxt[rn]=hd[x];hd[x]=rn;}
void init()
{
rn=;
memset(f,,sizeof(f));
memset(hd,,sizeof(hd));
memset(nxt,,sizeof(nxt));
}
void dfs(int now,int last)
{
int t1=hd[now],t2;
mx[now][]=mx[now][]=-INF;
mn[now][]=mn[now][]=INF;
mxbh[now]=;mnbh[now]=;
while(t1)
{
t2=tr[t1].y;
if(t2!=last)
{
dfs(t2,now);
if(f[t2][]>=mx[now][]){mx[now][]=mx[now][];mx[now][]=f[t2][];mxbh[now]=t2;}
else if(f[t2][]>mx[now][])mx[now][]=f[t2][];
if(f[t2][]<=mn[now][]){mn[now][]=mn[now][];mn[now][]=f[t2][];mnbh[now]=t2;}
else if(f[t2][]<mn[now][])mn[now][]=f[t2][];
}
t1=nxt[t1];
}
if(mx[now][]==-INF)mx[now][]=;
if(mn[now][]==INF)mn[now][]=;
//printf("%d:%lld %lld %lld\n",now,mx[now][0],mn[now][0],v[now]);
f[now][]=mx[now][]+v[now];
f[now][]=mn[now][]+v[now];
//printf("%d %lld %lld %lld\n",now,f[now][1],max1,v[now]);
}
void dfs2(int now,int last)
{
ans=max(ans,f[now][]);
//printf(" %d\n",now);
//for(int i=1;i<=n;i++)printf("%lld %lld:%d %d\n",f[i][0],f[i][1],mxbh[i],mnbh[i]);
//printf(" %lld %lld|%lld %lld\n",mx[now][0],mx[now][1],mn[now][0],mn[now][1]);
//printf("\n");
int t1=hd[now],t2;
ll fi0,fi1,fj0,fj1,tv,mxj0,mxj1,mnj0,mnj1;
int mxbhi,mxbhj,mnbhi,mnbhj;
while(t1)
{
t2=tr[t1].y;
if(t2!=last)
{
fi0=f[now][];fi1=f[now][];
fj0=f[t2][];fj1=f[t2][];
mxbhi=mxbh[now];mnbhi=mnbh[now];
mxbhj=mxbh[t2];mnbhj=mnbh[t2];
if(mxbh[now]==t2)
{
tv=v[now];
if(mx[now][]!=-INF)tv+=mx[now][];
f[now][]=tv;
}
if(mnbh[now]==t2)
{
tv=v[now];
if(mn[now][]!=INF)tv+=mn[now][];
f[now][]=tv;
}
mxj0=mx[t2][];mxj1=mx[t2][];
mnj0=mn[t2][];mnj1=mn[t2][];
if(mxbhj==)mx[t2][]=-INF;
if(mnbhj==)mn[t2][]=INF;
if(f[now][]>=mx[t2][]){mx[t2][]=mx[t2][];mx[t2][]=f[now][];mxbh[t2]=now;}
else if(f[now][]>mx[t2][])mx[t2][]=f[now][];
if(f[now][]<=mn[t2][]){mn[t2][]=mn[t2][];mn[t2][]=f[now][];mnbh[t2]=now;}
else if(f[now][]<mn[t2][])mn[t2][]=f[now][];
f[t2][]=mx[t2][]+v[t2];
f[t2][]=mn[t2][]+v[t2];
dfs2(t2,now);
f[now][]=fi0;f[now][]=fi1;
f[t2][]=fj0;f[t2][]=fj1;
mx[t2][]=mxj0;mx[t2][]=mxj1;
mn[t2][]=mnj0;mn[t2][]=mnj1;
mxbh[now]=mxbhi;mnbh[now]=mnbhi;
mxbh[t2]=mxbhj;mnbh[t2]=mnbhj;
}
t1=nxt[t1];
}
}
int main()
{
scanf("%d",&T);
int a,b;
while(T--)
{
init();
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%lld",&v[i]);
for(int i=;i<=n;i++){scanf("%d",&a);v[i]-=a;}
for(int i=;i<n;i++)
{
scanf("%d%d",&a,&b);
build(a,b);build(b,a);
}
memset(f,,sizeof(f));
dfs(,);
ans=-INF;
//for(int i=1;i<=n;i++)printf("%lld %lld/%lld %lld:%d %d %lld %lld\n",mx[i][0],mx[i][1],mn[i][0],mn[i][1],mxbh[i],mnbh[i],f[i][0],f[i][1]);
dfs2(,);
//ans=-INF;
//for(int i=1;i<=n;i++)ans=max(ans,f[i][1]);
//for(int i=1;i<=n;i++)printf("%lld %lld:%d %d\n",f[i][0],f[i][1],mxbh[i],mnbh[i]);
printf("%lld\n",ans);
}
return ;
}
心得:典型的树形DP的题目,换根时的操作还需要更多练习熟练
【HDU6662】Acesrc and Travel【树形DP】的更多相关文章
- 2019 Multi-University Training Contest 8 - 1006 - Acesrc and Travel - 树形dp
http://acm.hdu.edu.cn/showproblem.php?pid=6662 仿照 CC B - TREE 那道题的思路写的,差不多.也是要走路径. 像这两种必须走到叶子的路径感觉是必 ...
- 2019杭电多校 hdu6662 Acesrc and Travel (树形dp
http://acm.hdu.edu.cn/showproblem.php?pid=6662 题意:有两个人在树上博弈,每个点节点有两个分数a[i]和b[i],先手先选择一个点,后手在先手选的点的相邻 ...
- BZOJ.1576.[Usaco2009 Jan]安全路经Travel(树形DP 并查集)
题目链接 BZOJ 洛谷 先求最短路树.考虑每一条非树边(u,v,len),设w=LCA(u,v),这条边会对w->v上的点x(x!=w)有dis[u]+dis[v]-dis[x]+len的距离 ...
- 寒武纪-1005 Travel(树形DP)
一.题目链接 http://aiiage.hustoj.com/problem.php?id=1005 二.题面 PDF:http://aiiage.hustoj.com/upload/file/20 ...
- 【HDU6662】Acesrc and Travel(树型Dp)
题目链接 大意 给出一颗树,每个点上有一个权值\(A[i]\),有两个绝顶聪明的人甲和乙. 甲乙两人一起在树上轮流走,不能走之前经过的点.(甲乙时刻在一起) 甲先手,并可以确定起点.甲想要走过的点权之 ...
- HDU 6662 Acesrc and Travel (换根dp)
Problem Description Acesrc is a famous tourist at Nanjing University second to none. During this sum ...
- hdu 4612 Warm up 双连通+树形dp思想
Warm up Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total S ...
- HDU 6201 transaction transaction transaction(树形DP)
transaction transaction transaction Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 132768/1 ...
- HDU - 3899 JLUCPC(树形dp求距离和)
JLUCPC Dr. Skywind and Dr. Walkoncloud are planning to hold the annual JLU Collegiate Programming Co ...
随机推荐
- install mysql firewall
- 《图解设计模式》读书笔记3-2 Prototype模式
目录 Prototype(原型)模式的由来 类图 代码 角色 我的理解 Prototype(原型)模式的由来 创建一个实例,可以关键字new创建.但有时候,我们需要在不指定类名的前提下生成实例,比如: ...
- 测开之路六十:接口测试平台之common目录
实现接口测试平台使用jsonpath进行取值来断言,效果: 访问页面: 调试功能:http://www.kuaidi100.com/query 保存功能 触发执行功能 查看报告功能 目录结构 comm ...
- Vue访问子组件实例或子元素
1 尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件(例如,调用子组件的方法).为了达到这个目的,你可以通过 ref 特性为这个子组件赋予一个 ID 引用 ...
- Go-内存To Be
做一个快乐的互联网搬运工- 逃逸分析 逃逸分析的概念 在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法——分析在程序的哪些地方可以访问到指针. 它涉及到指针分析和形状分析. 当一个变量(或对 ...
- JSP基础--九大内置对象
JSP九大内置对象 Object findAttribute(String name):依次在page.request.session.application范围查找名称为name的数据,如果找到就停 ...
- init函数和匿名函数
init函数: 基本介绍: 每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用. 案例说明: //init函数,通常可以 ...
- python 分析 知乎粉丝数据
昨天花了一下午写了一个小爬虫,用来分析自己的粉丝数据.这个真好玩!今天帮了群里好多大V也爬了他们的数据.运行速度:每分钟5千粉丝以上.暂时先写成这样,这两天要准备补考,没有时间继续玩这个. 下次要改进 ...
- 【学习总结】Python-3-字符串函数split()的妙用
参考: 菜鸟教程-Python3-Python字符串-split() 语法: str.split(str="", num=string.count(str)) 参数 str -- ...
- unity DOTween Pro的使用--简化流程--自动播放
当gameobject setActive(true)的时候自动播放动画 1) 添加DoTween Animation. 设置动画效果, 略 选中 AutoPlay, 取消 AutoKill 2) 在 ...