【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 ...
随机推荐
- 【GDAL】聊聊GDAL的数据模型(二)——Band对象
在GDAL中栅格数据直接参与各种计算的重要对象是Band 摘录官方描述: Raster Band A raster band is represented in GDAL with the GDALR ...
- 死锁(Deadlock)
死锁:是指是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. ...
- vim插件管理器:Vundle的介绍及安装(很全)(转载)
转载自:https://blog.csdn.net/zhangpower1993/article/details/52184581 背景 Vim缺乏默认的插件管理器,所有插件的文件都散布在~/.vim ...
- 两数相加(java版本)
(一).单链表实现 package com.lin.leetcode.addTwoNumbers; /** * Created by Yaooo on 2019/8/26. */ public cla ...
- P2747 [USACO5.4]周游加拿大Canada Tour
题目描述 你赢得了一场航空公司举办的比赛,奖品是一张加拿大环游机票.旅行在这家航空公司开放的最西边的城市开始,然后一直自西向东旅行,直到你到达最东边的城市,再由东向西返回,直到你回到开始的城市.除了旅 ...
- Python自学第二天学习之《字符串与数字》
一.基本数据类型: 数字:int类型,不可变类型 格式 : a=10 1.其他类型转换成int型 : b=“123” c=int(b) #转换类型 print(c)----- 123 print(ty ...
- U33405 纽约 (二分)
[题目描述] 牧民 Azone 需要多次往返于两个草场之间运输家当.为了顺利转场,Azone 决定花费 w元津巴布韦币,购买一辆载重为 w 的汽车.共有 n 件家具需要搬运,每件家具的重量为 wi ...
- JVM(1)之 JAVA栈
开发十年,就只剩下这套架构体系了! >>> 若想使自己编写的Java程序高效运行,以及进行正确.高效的异常诊断,JVM是不得不谈的一个话题.本"JVM进阶"专 ...
- 【JAVA】 03-Java中的异常和包的使用
链接: 笔记目录:毕向东Java基础视频教程-笔记 GitHub库:JavaBXD33 目录: <> <> 内容待整理: 异常 异常和错误的发生和区别 异常:java运行期间发 ...
- 如何判断元素是否在可视区域内--getBoundingClientRect
介绍 Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置. 根据MDN文档 getBoundingClientRect 方法返回的是一个DOMRect ...