对于有向图$G$和起点$s$,有以下定义和性质——

为了方便,不妨假设$s$能到达$G$中所有点,并任意建立一棵以$s$为根的dfs树,以下节点比较默认均按照两点在这棵dfs树上的dfs序

支配点:$x$是$t$的支配点当且仅当将$x$以及相关的边删除后,不存在$s$到$t$的路径,也称作$x$支配$t$

(特别的,约定$s$和$t$均是$t$的支配点)

支配树:一棵以$s$为根的树,满足$t$的支配点恰是$t$到根的路径上所有点

引理1:若$x<y$,则$x$到$y$的路径(若存在)必然经过其$x$和$y$公共祖先

可以简单归纳证明,具体过程略

引理2:对于$t\ne s$,支配树上$t$的父亲为dfs树上$t$最深(且不为本身)的支配点(支配树存在且唯一)

注意到$t$的支配点必然是$t$或$t$在dfs树上的祖先,因此显然成立

记该点为$idom_{t}$,问题即如何求$idom$

半支配点:$x$是$t$的半支配点当且仅当存在一条$x$到$t$的路径,满足路径中所有点(除起点和终点外)均大于$x$

引理3:上述定义中,"所有点(除起点和终点外)均大于$x$"等价于"所有点(除起点外)均不是$x$的祖先

必要性显然,充分性根据引理1也显然

记$t$的半支配点中最小的为$semi_{t}$,考虑如何求$semi$

性质1:若$t\ne s$,则$semi_{t}=\min\{\min_{(x,t)\in E}x,\min_{k>t,k子树中\exists (x,t)\in E}semi_{k}\}$

若$(x,t)\in E$,显然$x$是$t$的半支配点,即有$semi_{t}\le x$

若$k>t$且$k$子树中$\exists (x,t)\in E$,那么构造路径$semi_{k}\rightarrow k\rightarrow x\rightarrow t$,显然$semi_{k}$也是$t$的半支配点,即有$semi_{t}\le semi_{k}$

结合两者,即得到左式$\le $右式

另一方面,考虑$semi_{t}$到$t$路径上最后一条边$(x,t)$,对其分类讨论:

1.若$x=semi_{t}$,即有$semi_{t}\ge \min_{(x,t)\in E}x$

2.若$x\ne semi_{t}$,取$semi_{t}$到$t$路径上$x$最浅的祖先$k$(除起点外),再考虑到$k$之前的这一段路径,结合引理3可得$semi_{t}$也是$k$的支配点,即有$semi_{t}\ge \min_{k>t,k子树中\exists (x,t)\in E}semi_{k}$

两者包含了所有情况,因此又得到左式$\ge$右式,即得证

引理4:若$t\ne s$,则$idom_{t}$是$semi_{t}$或其祖先,$semi_{t}$是$t$的祖先

前者根据定义显然,后者考虑$fa_{t}$总是$t$的半支配点,因此$semi_{t}\le fa_{t}<t$,再根据引理1也显然

性质2:若$t\ne s$,则$idom_{t}=\begin{cases}semi_{t}&(semi_{u}=semi_{t})\\idom_{u}&(semi_{u}<semi_{t})\end{cases}$(其中$semi_{u}=\min_{u\in 树链(semi_{t},t]}semi_{u}$)

(树链$(semi_{t},t]$指在dfs树上从$semi_{t}$到$t$的路径上除$semi_{t}$的点集)

(注意到$u$可以取$t$,那么显然$semi_{u}\le semi_{t}$)

对两种情况分别证明——

第一种情况下,注意到$semi_{t}$已经是$idom_{t}$的"下界",那么只需要证明其支配$t$即可

若$semi_{t}=s$显然成立,否则考虑反证法:

假设删除$semi_{t}$以及相关的边后还存在一条$s$到$t$的路径,考虑路径上最后一个是$semi_{t}$祖先的点$x$和之后第一个在树链$(semi_{t},t]$上的点$u$(由于$s$和$t$分别满足两者的条件,因此总存在)

考虑$x$到$u$的这一段,结合引理3可得$x$也是$u$的半支配点,与$semi_{u}$的最小性矛盾

第二种情况下,若$idom_{t}$不支配$u$,那么从$s$到$u$再到$t$即可(注意$idom_{t}\le semi_{t}<u$),再由$idom_{u}$的最小性得$idom_{t}\le idom_{u}$,因此$idom_{u}$同样是"下界",那么只需要证明其支配$t$即可

类似地定义$x$和$u$(将$semi_{t}$均变为$idom_{u}$),注意到$u$必然还在树链$(semi_{t},t]$上(否则显然$idom_{u}$不是$u$的支配点),进而同理$x$也是$u$的半支配点,与$semi_{u}$的最小性矛盾

另外,其实性质2有以下类似地描述(理解)方式——

性质2':若仅保留树边和$(semi_{t},t)$的边(其中$t\ne s$),得到的新图$G'$支配树与$G$相同

综合上述分析,来考虑具体的实现:

求$semi$——根据性质1,从后往前依次求,即支持单点修改、查询单点到根路径极值,由于其形式的特殊性可以用带权并查集维护,时间复杂度为$o(n\log n)$(仅路径压缩的并查集)

求$idom$——根据性质2,类似地求即可(注意顺序,需按照$semi$从后往前求出$u$,再从前往后求出$idom$),时间复杂度同样为$o(n\log n)$

最后建出支配树,再简单求和即可,时间复杂度为$o(n)$

最终,总复杂度为$o(n\log n)$​,可以通过

(另外,本题中若$s$不能到达$t$,则$t$的支配点仅定义为$s$和$t$)

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 200005
4 vector<int>v[N],rev_v[N],Q[N];
5 int n,m,x,y,dfn[N],pos[N],Fa[N],fa[N],mn[N],semi[N],idom[N],ans[N];
6 int get_min(int x,int y){
7 if (dfn[x]<dfn[y])return x;
8 return y;
9 }
10 int get_min_semi(int x,int y){
11 if (dfn[semi[x]]<dfn[semi[y]])return x;
12 return y;
13 }
14 int find(int k){
15 if (k==fa[k])return k;
16 int x=find(fa[k]);
17 mn[k]=get_min_semi(mn[k],mn[fa[k]]);
18 return fa[k]=x;
19 }
20 void update(int k){
21 fa[k]=Fa[k],mn[k]=k;
22 }
23 int query(int k){
24 find(k);
25 return mn[k];
26 }
27 void dfs(int k){
28 dfn[k]=++dfn[0],pos[dfn[0]]=k;
29 for(int i=0;i<v[k].size();i++)
30 if (!dfn[v[k][i]]){
31 Fa[v[k][i]]=k;
32 dfs(v[k][i]);
33 }
34 }
35 int main(){
36 scanf("%d%d",&n,&m);
37 for(int i=1;i<=m;i++){
38 scanf("%d%d",&x,&y);
39 v[x].push_back(y);
40 rev_v[y].push_back(x);
41 }
42 dfs(1);
43 int nn=dfn[0]++;
44 for(int i=1;i<=n;i++)fa[i]=i,mn[i]=0;
45 for(int i=nn;i>1;i--){
46 int t=pos[i];
47 for(int j=0;j<rev_v[t].size();j++){
48 semi[t]=get_min(semi[t],rev_v[t][j]);
49 semi[t]=get_min(semi[t],semi[query(rev_v[t][j])]);
50 }
51 Q[dfn[semi[t]]].push_back(t);
52 for(int j=0;j<Q[i].size();j++){
53 int t=Q[i][j];
54 idom[t]=query(t);
55 }
56 update(t);
57 }
58 for(int i=0;i<Q[1].size();i++){
59 int t=Q[1][i];
60 idom[t]=query(t);
61 }
62 for(int i=2;i<=nn;i++){
63 int t=pos[i];
64 if (semi[idom[t]]==semi[t])idom[t]=semi[t];
65 else idom[t]=idom[idom[t]];
66 }
67 for(int i=1;i<=n;i++)ans[i]=1;
68 for(int i=nn;i>1;i--){
69 int t=pos[i];
70 ans[idom[t]]+=ans[t];
71 }
72 ans[1]=n;
73 for(int i=1;i<n;i++)printf("%d ",ans[i]);
74 printf("%d\n",ans[n]);
75 return 0;
76 }

[luogu5180]支配树的更多相关文章

  1. 康复计划#4 快速构造支配树的Lengauer-Tarjan算法

    本篇口胡写给我自己这样的老是证错东西的口胡选手 以及那些想学支配树,又不想啃论文原文的人- 大概会讲的东西是求支配树时需要用到的一些性质,以及构造支配树的算法实现- 最后讲一下把只有路径压缩的并查集卡 ...

  2. [HDU]4694 Important Sisters(支配树)

    支配树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...

  3. luogu2597-[ZJOI2012]灾难 && DAG支配树

    Description P2597 [ZJOI2012]灾难 - 洛谷 | 计算机科学教育新生态 Solution 根据题意建图, 新建一个 \(S\) 点, 连向每个没有入边的点. 定义每个点 \( ...

  4. HDU.4694.Important Sisters(支配树)

    HDU \(Description\) 给定一张简单有向图,起点为\(n\).对每个点求其支配点的编号和. \(n\leq 50000\). \(Solution\) 支配树. 还是有点小懵逼. 不管 ...

  5. cf757F Team Rocket Rises Again (dijkstra+支配树)

    我也想要皮卡丘 跑一遍dijkstra,可以建出一个最短路DAG(从S到任意点的路径都是最短路),然后可以在上面建支配树 并不会支配树,只能简单口胡一下在DAG上的做法 建出来的支配树中,某点的祖先集 ...

  6. 2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)

    题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的 ...

  7. [BZOJ2815][ZJOI2012]灾难(拓扑排序/支配树)

    支配树目前只见到这一个应用,那就不独分一类,直接作为拓扑排序题好了. 每个点向所有食物连边,定义fa[x]为x的支配点,即离x最近的点,满足若fa[x]灭绝,则x也要灭绝. 这样,将fa[x]向x连边 ...

  8. 51nod2004 终结之时 (支配树+树剖+树链的并)

    link 我永远喜欢洛天依 给定一张图世末积雨云,你需要维护其支配树: 单点修改,子树修改,树链修改 子树求和,树链求和,多条树链的并集求和 撤销之前的操作 可以先用 Lengauer-Tarjan ...

  9. codeforces757F Team Rocket Rises Again【支配树+倍增+拓扑+spfa】

    先跑spfa求出最短路构成的DAG,然后在DAG上跑出支配树dfs出size取max即可 关于支配树,因为是DAG,支配点就是入点在支配树上的lca,所以一边拓扑一边预处理倍增,然后用倍增求lca # ...

随机推荐

  1. 理解hashMap

    首先需要理解几个基本概念: 什么是数据结构?(摘自 java数据结构系列--什么是数据结构 (baidu.com)) 数据结构是计算机组织.存储数据的方式.简单来说就是,数据按指定的规则进行存储,从而 ...

  2. 题解 CF833D Red-Black Cobweb

    题目传送门 题目大意 给出一个 \(n\) 个点的树,每条边有边权和颜色 \(0,1\) ,定义一条链合法当且仅当 \(0,1\) 颜色的边数之比小于等于 \(2\) ,求所有合法的链的边权之积的积. ...

  3. 掌握BeanShell,轻松处理jmeter中的数据

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15424558.html 博客主页:https://www.cnblogs.com/testero ...

  4. 3 Implementation: The Big Picture 实现:蓝图

    三.Implementation: The Big Picture 实现:蓝图 3.1 Layering of a .NET Solution .Net解决方案的分层 The picture belo ...

  5. python解释器和Pycharm编辑器安装使用完整详细教程

    一.官网下载或软件管家公众号下载 二.安装Python解释器 1.选择自定义安装并添加到环境变量 2.检验Python是否安装成功 三.安装pycharm编辑器 1.点击安装,修改安装路径,建议安装C ...

  6. CentOS 用户与群组

    目录 1.用户管理 1.1.切换用户 1.2.添加用户 1.3.删除用户 1.4.修改用户 2.群组管理 2.1.查看群组 2.2.添加群组 2.3.删除群组 2.4.修改群组 1.用户管理 Linu ...

  7. 第七次Scrum Metting

    日期:2021年5月5日 会议主要内容概述:前后端对接,以及接下来的测试优化等工作. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 测试数据模块和 ...

  8. WEB前端工程师如何做职业规划?

    对于一个WEB前端的职业规划,其实是有各种的答案,没有哪种答案是完全正确的,全凭自己的选择,只要是自己选定了,坚持去认真走,就好.在这里, 我只是 简要说一下自己对于这块儿内容的理解.有一个观点想要分 ...

  9. Spring Security:Servlet 过滤器(三)

    3)Servlet 过滤器 Spring Security 过滤器链是一个非常复杂且灵活的引擎.Spring Security 的 Servlet 支持基于 Servlet 过滤器,因此通常首先了解过 ...

  10. Java设计模式——模板设计模式

    模板设计模式 1.模板模式简介 模板模式(Template ):模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑 ...