Ancestral Problem 题解

news/2025/10/21 21:42:02/文章来源:https://www.cnblogs.com/HaHeHyt/p/19156376

匈牙利吊打 dinic

下面默认二分图匹配的复杂度是 \(\mathcal{O}(m\sqrt n)\),其中 \(n\) 是点数,\(m\) 是边数。

暂时默认 \(m=\mathcal{O}(n)\) 因为不影响分析复杂度。


首先容易写出 \(\mathcal{O}(n^{3.5})\)dp

钦定第二棵树以 \(1\) 为根,枚举第一棵树的根,然后记 \(f_{x,i}\) 表示第一棵树的 \(x\) 子树能否和第二棵的 \(i\) 子树匹配。

转移就把 \(x,i\) 的所有儿子拎出来,通过之前 dp 值把能匹配的连边,然后判断二分图是否存在完美匹配。


你思考第一棵树本质不同的子树状态只有 \(\mathcal{O}(n)\) 个并非 \(\mathcal{O}(n^2)\) 个。

这时你直接记忆化 \(f_{(x,fa),y}\) 表示第一棵树的以 \(fa\) 为根的 \(x\) 子树能否和第二棵的 \(y\) 子树匹配。

递归下去也是记忆化。

这样就 \(\mathcal{O}(n^{2.5})\) 了吗?并非,因为你还要枚举儿子。

直接来两个菊花就给你卡掉了。


考虑换根 dp,记 \(f_{x,i}\) 表示以 \(1\) 为根,第一棵树的 \(x\) 子树能否和第二棵的 \(i\) 子树匹配。这个是容易求的。

然后换根记 \(g_{x,i}\) 表示以 \(x\) 根,第一棵树的 \(fa_x\) 子树能否和第二棵的 \(i\) 子树匹配。

考虑已知 \(f\),已知 \(g_{x,*}\) 如何转移得到 \(g_{y,*}\),其中 \(y\)\(x\) 的儿子。

根据已知,我们能知道以 \(x\) 为根的时候,\(x\) 的邻域和第二棵树能否匹配。其中儿子 \(u\) 通过 \(f_u\) 得到,父亲通过 \(g_{x}\) 得到。

然后我们直接和某个点 \(i\) 匹配。此时若某个儿子 \(y\)\(x\)\(i\) 匹配的必经点,则 \(g_{y,i}=0\),否则 \(g_{y,i}=1\)

二分图匹配必经点

  • 结论是:非必经点 左部是 \(S\) 走残量网络中边权为 \(1\) 的边能走到的所有左部点,右部是 \(T\) 走残量网络中边权为 \(0\) 的边能走到的所有右部点。

于是所有复杂度都对了,复杂度 \(\mathcal{O}(nm\sqrt n)\),理论根本过不去,但是 dinic 小常数跑不满导致能过。


卡时卡空间注意几点:

  • 图的边权要开到 \(nm+n+m\),否则可能被卡。

  • 前向星存图的几个数组分开放。

  • dp 数组 \(f,g\),以及图的边权都用 \(2\times 10^7\)bitset 存储。

  • 可以把 dfs 序存下来做后面的 dfs

  • 进行必要的剪枝。

于是你写出了如下代码,足以通过:

#include<bits/stdc++.h>
#define LL long long
#define u64 unsigned long long
#define sz(x) ((int)x.size())
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
inline void rd(int &x){x=0;char c=getchar();while(!isdigit(c)) c=getchar();while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
const int N=2e5+5,M=2e7+2e5+5;
int n,m,S,T,fa[N];bool ok,v[N];
bitset<M>f,g;
basic_string<int>G1[N],G2[N],tn;
namespace FL
{int hd[N],_hd[N],tt,d[N],to[M],nx[M];bitset<M>W;inline void add(int u,int v,int w){to[++tt]=v,nx[tt]=hd[u],W[tt]=w,hd[u]=tt;to[++tt]=u,nx[tt]=hd[v],W[tt]=0,hd[v]=tt;}inline void cl(){fill_n(hd,T+1,0);tt=1;}inline bool bfs(){fill_n(d,T+1,0);d[S]=1;queue<int>q;q.push(S);while(!q.empty()){int t=q.front();q.pop();for(int i=hd[t];i;i=nx[i]){int y=to[i];if(!d[y]&&W[i]) d[y]=d[t]+1,q.push(y);}}return d[T];}int dfs(int x,int F){if(x==T) return F;int o=F;for(int &i=_hd[x];i;i=nx[i]){int y=to[i];if(d[y]==d[x]+1&&W[i]){int t=dfs(y,min(o,(int)W[i]));if(t) o--,W[i].flip(),W[i^1].flip();if(!o) break;}}return (o==F)&&(d[x]=0),F-o;}inline int dinic(){int s=0;while(bfs()) memcpy(_hd,hd,(T+1)<<2),s+=dfs(S,1e9);return s;}void DFS(int x){v[x]=1;for(int i=hd[x];i;i=nx[i]){int y=to[i];if(W[i]&&!v[y]) DFS(y); }}inline void get(){fill_n(v,T+1,0),DFS(S);}
}
void I(int x,int F)
{if(F) G2[x].erase(find(G2[x].begin(),G2[x].end(),F));for(int y:G2[x]) I(y,x);
}
inline int W(int i,int j){return (i-1)*m+j;}
void dfs(int x,int F)
{tn+=x;fa[x]=F;if(sz(G1[x])==1&&G1[x][0]==F){for(int i=1;i<=m;i++) if(!sz(G2[i])) f.set(W(x,i));return;}basic_string<int>g;for(int y:G1[x]) if(y^F) dfs(y,x),g+=y;for(int y=1;y<=m;y++){int A=sz(g),B=sz(G2[y]);if(A<B) continue;FL::cl();S=0;T=A+B+1;for(int i=1;i<=A;i++) FL::add(S,i,1);for(int i=1;i<=B;i++) FL::add(i+A,T,1);for(int i=0;i<A;i++) for(int j=0;j<B;j++)if(f[W(g[i],G2[y][j])]) FL::add(i+1,j+A+1,1);if(FL::dinic()^B) continue;if(y==1) return ok=1,void();f.set(W(x,y));}if(ok) return;
}
int main()
{int _;rd(_);while(_--){for(int i=1;i<=n;i++) G1[i].clear();for(int i=1;i<=m;i++) G2[i].clear();rd(n);for(int i=1,u,v;i<n;i++) rd(u),rd(v),G1[u]+=v,G1[v]+=u;rd(m);for(int i=1,u,v;i<m;i++) rd(u),rd(v),G2[u]+=v,G2[v]+=u;for(int i=0;i<=n*m;i++) f[i]=g[i]=0;if(m>n){puts("NO");continue;}if(m==1){puts("YES");continue;}ok=0;I(1,0);tn.clear();dfs(1,0);if(ok){puts("YES");continue;}for(int x:tn){int F=fa[x];for(int y=1;y<=m;y++){int A=sz(G1[x]),B=sz(G2[y]);if(A<B) continue;FL::cl();S=0;T=A+B+1;for(int i=1;i<=A;i++) FL::add(S,i,1);for(int i=1;i<=B;i++) FL::add(i+A,T,1);for(int i=0;i<A;i++) for(int j=0;j<B;j++){int X=G1[x][i],Y=G2[y][j];if(X==F?g[W(x,Y)]:f[W(X,Y)]) FL::add(i+1,j+A+1,1);}if(FL::dinic()^B) continue;if(y==1){ok=1;break;}FL::get();for(int i=0;i<A;i++) if(v[i+1]&&G1[x][i]!=F) g.set(W(G1[x][i],y));}if(ok) break;}puts(ok?"YES":"NO");}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/942688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AWS IAM角色最佳实践:构建云安全的核心防线

本文深入探讨AWS IAM角色的核心概念与最佳实践,涵盖身份识别、权限管控、威胁检测和自动响应等关键环节,通过具体配置示例展示如何有效保护云环境安全,避免权限滥用和潜在威胁。AWS IAM角色最佳实践 Amazon Web Ser…

初始人工智能和机器学习

一、初始人工智能 1.人工智能是一个抽象的概念,它不是任何具体的机器或算法。任何类似于人的智能或高于人的智能的机器或算法都可以称为人工智能。应用:机器人等。 2.机器学习是AI系统需要具备自我学历的能力,即从原…

盒子模型外边距合并问题

两个外边距重合时,那个大用哪个 当只给子级盒子创建顶部外边距时,会连带着父级盒子一起隔离 第一种:取消子级外边距,给父级加内边距(加内边距会撑大盒子) 规避撑大盒子 2.给父级溢出的部分给隐藏 3.加细边框线显示出多…

o(N^2)找出所有回文子串

1、对于一个字符串如果(i - 1, j - 1)为回文串,并且s[i] == s[j],那么(i, j)也是一个回文串 2、双重循环,外层从大到小,内层从小到大,这样就可以由小区间推到大区间(可以写下思考一下)int vis[2010][2010];mems…

蛋白表达技术概述

一、蛋白表达的定义 蛋白表达(Protein Expression) 是指通过人工构建的基因表达系统,在特定宿主细胞中合成目标蛋白的过程。在自然界中,基因经转录和翻译形成蛋白质,这是生命活动的基本过程。在实验和工业生产中,…

二叉树的中序遍历- 递归原理 - MKT

二叉树的中序遍历- 递归原理

二叉树的中序遍历- 二叉树基本-栈 - MKT

二叉树的中序遍历- 二叉树基本-栈 前序遍历非递归实现​​:void preorderIterative(TreeNode* root) {if (root == nullptr) return;stack<TreeNode*> s;s.push(root);while (!s.empty()) {TreeNode* node = s…

二叉树的中序遍历- 二叉树基本-递归 - MKT

二叉树的中序遍历- 二叉树基本-递归 #include <iostream> #include <queue> using namespace std;struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr…

二叉树的中序遍历- 递归和栈 - MKT

二叉树的中序遍历- 递归和栈 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) …

构建YouTube视频总结摘要智能体

构建YouTube视频总结摘要智能体智能体 AI 平台 智能体 AI 框架是一个工具包,用于创建能够通过工具使用和记忆自主或半自主地推理、计划和采取行动的智能体系统。这些框架提供了创建能够与环境交互、做出决策和执行…

友链测试

// run new Vue({el: #app,data: {links: [{name: 捞月亮の小北,desc: 言念君子,温其如玉,avatar: https://youke1.picui.cn/s1/2025/10/21/68f785af89315.png,url: https://example.com},{name: Fomalhaut,desc: Fut…

English writing practice in diary.

Recent Situation Overview Currently everything around is horrible, but hopful(hopeful) too. Learning English for TOEFL, studying major ourse for upgradation(academic improvement) and devoting in web3 r…

以此文记我的国漫生活

原来我以前看过这么多动画片和动漫,来看看你看过哪些: 《喜羊羊与灰太狼》《熊出没》《猪猪侠》《猫和老鼠》《成龙历险记》《十二生肖闯江湖》《大头儿子和小头爸爸》《神兵小将》《舒克贝塔》《疯狂小糖》《葫芦娃…

做了一个概率小游戏,没想到服务器被打爆被攻击了!原因竟然是他?真没想到...

做了一个概率小游戏,没想到服务器被打爆被攻击了!原因竟然是他?真没想到。让我给大家讲讲我怎么和攻击者在线上斗智斗勇的。1. 前言 事情是这样的,上个月在刷知乎的过程中,发现了以下几个有趣的问题。《每毫秒给你…

接下来的目标

本学期目标: 1.学完redis黑马点评,掌握关于redis,分布式锁,秒杀等知识点 2.八股文在javaguide上观看一遍 3.算法题hot100刷第一遍 4.看完《深入理解jvm虚拟机》目前已看完历史即第一章,准备编译openjdk12; 5.写完…

敬启,致那时的我

题面 题目描述 实乃理给你两个整数 \(S, k\),你需要帮她求出以下式子的值对 \(1,000,000,007\) 取模的结果: \[\sum_{X = 0}^S [\mathrm{popc}(X) = k]F(X) \]其中 \(F\) 为斐波那契数列,即 \(F(0) = F(1) = 1, F(n…

阿里云对象存储OSS之Java - Soul

阿里云对象存储OSS 介绍阿里云对象存储OSS是一款非常强大的云存储服务——提供的海量、安全、低成本、高持久性的对象存储服务,通过RESTful API提供HTTP接口。 核心特性:无限扩展:存储空间和文件数量无上限。 多存储…

清楚标签默认样式,内容溢出盒子时的处理

所有标签都有默认样式 scroll:无论是否一处都显示水平和竖直的滚动条, auto:只有当水平或者竖直方向移出时才会显示

Solidity合约继承场景下的构造函数执行顺序

Solidity合约继承场景下的构造函数执行顺序“从远到近,从左到右” 举例,TetherToken有如下继承关系: TetherToken is Pausable, StandardToken, BlackList多重继承时,"从左到右",先初始化 Pausable,再…

后量子密码学技术与标准化进程解析

本文深入探讨后量子密码学技术发展现状,涵盖NIST标准化进程、密码算法创新及实际部署方案。重点分析SPHINCS+签名框架、混合密钥交换机制在TLS协议中的实现,以及云计算环境下的技术迁移路径。为后量子密码学未来做好…