对于有向图$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. JS中变量的命名规范

    命名规范 包含数字.字母.下划线和$,但 不能以数字开头 变量名严格区分大小写 变量名不能是关键字和保留字 变量名要见名知意 如果变量名有多个单词组成,推荐使用 小驼峰命名法 命名时,尽量使用英语,如 ...

  2. MacOS上通过虚拟机搭建基础CentOS7系统环境

    MacOS上通过虚拟机搭建基础CentOS7系统环境 尽管从Mac的Terminal可以看出,macOS与UNIX.Linux或多或少都有血缘关系(shell.bash等),但是在mac进行Linux ...

  3. nginx配置禁止爬虫配置

    1.在配置文件里添加禁止爬虫配置 server { ------ #添加如下内容即可防止爬虫 if ($http_user_agent ~* "qihoobot|Baiduspider|Go ...

  4. 如何用redis统计海量UV?

    前言 我们先思考一个常见的业务问题:如果你负责开发维护一个大型的网站,有一天老板找产品经理要网站每个网页每天的 UV 数据,然后让你来开发这个统计模块,你会如何实现? 统计uv的常用方法以及优缺点 其 ...

  5. Serverless 在编程教育中的实践

    说起Serverless这个词,我想大家应该都不陌生,那么Serverless这个词到底是什么意思?Serverless到底能解决什么问题?可能很多朋友还没有深刻的体会和体感,这篇文章我就和大家一起聊 ...

  6. 题解 「2017 山东一轮集训 Day7」逆序对

    题目传送门 Description 给定 $ n, k $,请求出长度为 $ n $ 的逆序对数恰好为 $ k $ 的排列的个数.答案对 $ 10 ^ 9 + 7 $ 取模. 对于一个长度为 $ n ...

  7. css3鼠标悬停图片边框线条动画特效

    css3鼠标经过内容区时,边框线条特效效果制作.   html: <div class="strength grWidth hidden"> <div class ...

  8. JVM:Java中的引用

    JVM:Java中的引用 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 在原来的时候,我们谈到一个类的实例化 Person p = new Person() 在 ...

  9. RogrePirates Scrum Meeting 博客汇总

    RogrePirates 博客目录 一.Scrum Meeting 1.Alpha阶段 第一次会议 第二次会议 第三次会议 第四次会议 第五次会议 第六次会议 第七次会议 第八次会议 第九次会议 第十 ...

  10. Spark面试题(二)

    首发于我的个人博客:Spark面试题(二) 1.Spark有哪两种算子? Transformation(转化)算子和Action(执行)算子. 2.Spark有哪些聚合类的算子,我们应该尽量避免什么类 ...