正题

题目链接:https://www.luogu.com.cn/problem/P7443?contestId=41429


题目大意

\(n\)个点的一棵有根树,两个人从一号点开始进行有向图博弈。

告诉你Alice是先手还是后手,然后你可以选择加一条链接\((u,v)\)的有向边,权值为\(A\times a_u+B\times a_v\)。求最小权值使得第一个人获胜。(如果死循环则无法获胜)

\(1\leq T\leq 2\times 10^3,2\leq n\leq 2\times 10^5,\sum n\leq 5\times 10^6,1\leq a_i,A,B\leq 10^9\)


解题思路

先考虑没有加边情况的胜负。定义\(1\)为先手必败状态,那么所有叶子都是\(1\)。然后每个节点是所有子节点的或值再异或\(1\)。

那么如果已经必胜就是\(0\)了,否则我们需要改变一号节点的状态。

先考虑加一条返祖边的影响,首先这条边肯定是加在Alice行动的节点上,否则Bob可以选择不走。

而且\(v\)肯定得是先手必败的局面,否则没有意义。然后如果\(v\)是先手必败的话,那么Bob显然还是可以往之前的路径走,如果走到\(u\)节点时是Alice移动那么状态不会改变,否则Bob可以继续走返祖边造成死循环。所以返祖边不能影响状态。

然后考虑翻转一个点的状态需要做什么。

如果这个点是先手必败,那么我们只需要找到另一个先手必败的节点连接过去或者翻转子节点的状态就可以翻转该节点的状态。

如果这个点是先手必胜,那么如果子节点中有两个或以上的先手必败那么该节点无法翻转,否则翻转那个先手必败的节点即可。

那么现在我们需要解决寻找除了该节点到根的路径上的点中权值最小的先手必败节点权值。

用优先队列的话会\(TLE\),所以我们考虑其他方法,我们对于每个节点记录一下子树中最大的先手必败节点权值,然后每次向下递归的时候就取所有除了递归子树以外的子节点子树丢进最小值就好了。

这个记录一个次大值和最大值就可以实现。

时间复杂度\(O(\sum n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<queue>
#define ll long long
using namespace std;
const ll N=2e5+10;
struct node{
ll to,next;
}a[N];
ll T,n,m,t,A,B,tot,w[N],fa[N],z[N];
ll ls[N],f[N],s[N],ans;
ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
void addl(ll x,ll y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(ll x){
f[x]=s[x]=0;z[x]=1e9+7;
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
dfs(y);f[x]|=f[y];s[x]+=f[y];
z[x]=min(z[x],z[y]);
}
f[x]^=1;
if(f[x])z[x]=min(z[x],w[x]);
return;
}
void dp(ll x,ll mins){
ll c=mins,zc=mins;
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(z[y]<c)zc=c,c=z[y];
else if(z[y]<zc)zc=z[y];
}
if(f[x]){
for(ll i=ls[x];i;i=a[i].next)
dp(a[i].to,(z[a[i].to]==c)?zc:c);
if(c!=1e9+7)ans=min(ans,w[x]*A+c*B);
}
else if(s[x]==1){
for(ll i=ls[x];i;i=a[i].next)
if(f[a[i].to])dp(a[i].to,(z[a[i].to]==c)?zc:c);
}
}
signed main()
{
T=read();
while(T--){
n=read();t=read();A=read();B=read();
for(ll i=1;i<=n;i++)ls[i]=0;tot=0;
for(ll i=2;i<=n;i++)fa[i]=read(),addl(fa[i],i);
for(ll i=1;i<=n;i++)w[i]=read();
dfs(1);
if(f[1]^t^1){puts("0");continue;}
else{
ans=3e18;dp(1,1e9+7);
if(ans==3e18) puts("-1");
else printf("%lld\n",ans);
}
}
}

P7443-加边【博弈论】的更多相关文章

  1. 博弈论入门小结 分类: ACM TYPE 2014-08-31 10:15 73人阅读 评论(0) 收藏

    文章原地址:http://blog.csdn.net/zhangxiang0125/article/details/6174639 博弈论:是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策 ...

  2. 博弈论之Nim

    博弈论(一):Nim游戏 重点结论:对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0,其中^表示位异或(xor)运算. Nim游戏是博 ...

  3. 博弈论中的Nim博弈

    瞎扯 \(orzorz\) \(cdx\) 聚聚给我们讲了博弈论.我要没学上了,祝各位新年快乐.现在让我讲课我都不知道讲什么,我会的东西大家都会,太菜了太菜了. 马上就要回去上文化课了,今明还是收下尾 ...

  4. 博弈论简单入门sb总结

    博弈论简单入门sb总结 下午讲博弈论.没预习,GG. 整个下午都在学. 0 有一堆共n个石子,两个人轮流取石子,每个人一次可以取1到k个,取到最后一个石子的人胜利. 小学生都会的sb题.若k+1|n, ...

  5. 【uoj#51】[UR #4]元旦三侠的游戏 博弈论+dp

    题目描述 给出 $n$ 和 $m$ ,$m$ 次询问.每次询问给出 $a$ 和 $b$ ,两人轮流选择:将 $a$ 加一或者将 $b$ 加一,但必须保证 $a^b\le n$ ,无法操作者输,问先手是 ...

  6. [您有新的未分配科技点]博弈论进阶:似乎不那么恐惧了…… (SJ定理,简单的基础模型)

    这次,我们来继续学习博弈论的知识.今天我们会学习更多的基础模型,以及SJ定理的应用. 首先,我们来看博弈论在DAG上的应用.首先来看一个小例子:在一个有向无环图中,有一个棋子从某一个点开始一直向它的出 ...

  7. [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)

    今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...

  8. 三十分钟理解博弈论“纳什均衡” -- Nash Equilibrium

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 纳什均衡(或者纳什平衡),Nash ...

  9. xtuoj 1235 CQRXLB(博弈论)

    CQRXLB Accepted : 19   Submit : 40 Time Limit : 1000 MS   Memory Limit : 65536 KB CQRXLB Problem Des ...

  10. HDU 5299 Circles Game 博弈论 暴力

    Circles Game 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5299 Description There are n circles on ...

随机推荐

  1. C# lock的语法糖原理--《.net core 底层入门》之自旋锁,互斥锁,混合锁,读写锁

    在多线程环境中,多个线程可能会同时访问同一个资源,为了避免访问发生冲突,可以根据访问的复杂程度采取不同的措施 原子操作适用于简单的单个操作,无锁算法适用于相对简单的一连串操作,而线程锁适用于复杂的一连 ...

  2. (强制)要求覆写equals必须覆写hashCode(原理分析)

    hashCode和equals hashCode和equals用来标识对象,两个方法协同工作可用来判断两个对象是否相等.众所周知,根据生成的哈希将数据散列开来,可以使存取元素更快.对象通过调用Obje ...

  3. Mybatis中多表联查,查询出来的字段出现重名,造成数据异常的解决方法!

    在做一对多出现的问题,引发的思考:当数据库表中,主表的主键id和明细表的中的字段名相同时怎么办?Mybatis进行自动映射赋值的时候会不会出现异常?                      注意:M ...

  4. VPS系统后台性能优化实战

    作者: 刘用, 现任新东方APP团队高级软件工程师 2019年开始,新东方APP团队启动了长达半年以上的稳定性建设工作,为什么稳定性如此重要?因为随着每年30%以上的高速增长,现有的后端服务完全扛不住 ...

  5. 取消Ubuntu开机硬盘自检

    修改/etc/fstab文件,最后一列全改为0,测试能正常启动,尚未出现再次自检的情况 sudo gedit /etc/fstab

  6. Shell中常用的语句

    exit 完全中断脚本的执行 break 中断脚本的循环,但是会执行循环外的语句 continue 跳出本次循环,进行下一次循环 进一步了解三者的区别,有如下实验: 执行该脚本: 脚本正常运行情况: ...

  7. inotify与rsync实现实时同步记录文档

    目录 安装 配置 参考链接 安装 安装rsync yum -y install rsync 安装inotify-tools 这是一个实时监听文件变换的工具 wget -O /etc/yum.repos ...

  8. 开源的 Web 框架哪个快?我在 GitHub 找到了答案

    在开源这片自由的土地上,孕育了太多开源 Web 框架.我在 GitHub 上搜了一下"web framework"关键字显示有 56000+ 匹配的开源项目,它们百花齐放各有特色, ...

  9. ---Docker学习随笔---基础管理部分---

    docker是什么?提供快速.高效.轻量的微服务平台 1. 背景介绍突破虚拟机对资源占用高.启动时间长.镜像存储大.集群规模小等限制,摆脱操作系统级的隔离级别,实现进程级管理.主要专用名词: chro ...

  10. Python - 面向对象编程 - __init__() 构造方法

    什么是构造方法 在创建类时, 可手动添加一个   __init__() 方法,称为构造方法,这是一个实例方法 构造方法用于创建实例对象时使用,每当创建一个类的实例对象时,Python 解释器都会自动调 ...