正题

题目链接: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. flutter中修改键盘状态

    当用户进行表格输入时,为更方便的方便用户操作,我们需要设置键盘状态方便用户点击,如当表格填写完成时,用户可以直接点击键盘下面的"完成"状态完成提交. 实现如下: TextFormF ...

  2. flutter canvas圆圈转圈动画

    import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runA ...

  3. Elastic_Search 和java的入门结合

    1, pom 文件添加依赖... 2, config 配置文件 3, 写接口文件

  4. 关于servlet中要写初始化逻辑应该重载有参还是无参的init

    关于开发者在写初始化逻辑的时候,应该选用的哪个init方法@author mzy 在查看servlet的源码的时候,因为servlet是一个接口使用较麻烦: 所以我们使用它的实现类:GenericSe ...

  5. docker安装与配置nginx详细过程

    注:大鸟飞过,此方式只用于快速搭建使用 第一步 pull nginx 命令:docker pull nginx 第二步 启动nginx 命令:docker run --name nginx -p 80 ...

  6. rabbitMq可靠消息投递之交换机备份

    //备份队列 @Bean("alternate_queue") public Queue alternate_queue() { return new Queue("al ...

  7. vue3.0入门(一)

    前言 最近在b站上学习了飞哥的vue教程 学习案例已上传,下载地址 使用方式 使用在线cdn 下载js文件并自托管,引入到项目后使用 使用npm安装后,用cli来构建项目 声明式渲染 Vue2需引入v ...

  8. 谈谈redis缓存击穿透和缓存击穿的区别,雪崩效应

    面试经历 在很长的一段时间里,我以为缓存击穿和缓存穿透是一个东西,直到最近去腾讯面试,面试官问我缓存击穿和穿透的区别:我回答它俩是一样的,面试官马上抬起头用他那细长的单眼皮眼睛瞪着我说:"你 ...

  9. Mybatis-plus<三> MybatisPlus条件构造器

    Mybatis-plus<三> MybatisPlus条件构造器 Demo GitHub下载地址:https://github.com/RJvon/Mybatis_plus_demo My ...

  10. SQL语句之基本使用

    1.sql语法 一些重要的SQL命令: SELECT - 从数据库中提取数据 UPDATE - 更新数据库中的数据 DELETE - 从数据库中删除数据 INSERT INTO - 向数据库中插入新数 ...