支配树(洛谷-P5180)
题目描述
给定一张有向图,求从1号点出发,每个点能支配的点的个数(包括自己)
输入输出格式
输入格式:
第一行两个正整数n,mn,m,表示点数和边数 接下来mm行,每行输入两个整数u,vu,v,表示有一条uu到vv的有向边
输出格式:
一行输出nn个整数,表示每个点能支配的点的个数
输入输出样例
输入样例#1:
10 15
1 2
2 3
3 4
3 5
3 6
4 7
7 8
7 9
7 10
5 6
6 8
7 8
4 1
3 6
5 3输出样例#1:
10 9 8 4 1 1 3 1 1 1
思路:求一般有向图的支配点,支配树的 Lengauer Tarjan 算法模板题
源代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<LL,LL>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-10;
const int MOD = 998244353;
const int N = 400000+5;
const int dx[] = {-1,1,0,0,1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;struct MAP {struct Edge {int to, next;} edge[N << 1];int tot, head[N];void addEdge(int x, int y) {edge[++tot].to = y;edge[tot].next = head[x];head[x] = tot;}
};
MAP G, GF; //原图、反图
MAP dfsTree, dfsTreeF; // dfs树、dfs树的反图
MAP dominate; //支配树MAP xx;
int n, m;
int father[N]; // dfs树上的父节点
int dfn[N], id[N], tim; // dfs序、标号、时间戳void dfs(int x) {id[++tim] = x;dfn[x] = tim;for (int i = G.head[x]; i; i = G.edge[i].next) {int to = G.edge[i].to;if (!dfn[to]) {dfs(to);father[to] = x;dfsTree.addEdge(x, to);}}
}int sdom[N]; //半支配点
int mn[N]; // mn[i]表示i点的dfs树上的sdom最小的祖先,因此有sdom[mn[i]]=sdom[i]
int anc[N]; // anc[i]代表i的祖先
int find(int x) { //路径压缩的带权并查集if (x != anc[x]) {int t = anc[x];anc[x] = find(anc[x]);if (dfn[sdom[mn[x]]] > dfn[sdom[mn[t]]])mn[x] = mn[t];}return anc[x];
}
void LengauerTarjan() { //寻找半支配点for (int i = 1; i <= n; i++) {anc[i] = i;sdom[i] = i;mn[i] = i;}for (int j = n; j >= 2; j--) {int x = id[j];if (!x)continue;int pos = j;for (int i = GF.head[x]; i; i = GF.edge[i].next) {int y = GF.edge[i].to;if (!dfn[y])continue;if (dfn[y] < dfn[x])pos = min(pos, dfn[y]);else {find(y); //寻找树上y的一个满足dfn[z]>dfn[x]的祖先zpos = min(pos, dfn[sdom[mn[y]]]);}}sdom[x] = id[pos];anc[x] = father[x];dfsTree.addEdge(sdom[x], x); //在dfs树上连边}
}int deep[N], dp[N][25];
int getLCA(int x, int y) { //获取LCAif (deep[x] < deep[y])swap(x, y);int del = deep[x] - deep[y];for (int i = 0; i <= 20; i++)if ((1 << i) & del)x = dp[x][i];if (x == y)return x;for (int i = 20; i >= 0; i--) {if (dp[x][i] != dp[y][i]) {x = dp[x][i];y = dp[y][i];}}return dp[x][0];
}
void buildDominate(int x) { //建立支配树int to = dfsTreeF.edge[dfsTreeF.head[x]].to;for (int i = dfsTreeF.head[x]; i; i = dfsTreeF.edge[i].next) {int y = dfsTreeF.edge[i].to;to = getLCA(to, y);}deep[x] = deep[to] + 1;dp[x][0] = to;dominate.addEdge(to, x);for (int i = 1; i <= 20; i++)dp[x][i] = dp[dp[x][i - 1]][i - 1];
}
int in[N]; // dfs树的入度
void topSort() {for (int i = 1; i <= n; i++) {for (int j = dfsTree.head[i]; j; j = dfsTree.edge[j].next) {int to = dfsTree.edge[j].to;in[to]++;dfsTreeF.addEdge(to, i); //对DFS树的反图建边}}for (int i = 1; i <= n; i++) {if (!in[i]) {dfsTree.addEdge(0, i); // dfs树建边dfsTreeF.addEdge(i, 0); // dfs树的反图建边}}queue<int> Q;Q.push(0);while (Q.size()) {int x = Q.front();Q.pop();for (int i = dfsTree.head[x]; i; i = dfsTree.edge[i].next) {int y = dfsTree.edge[i].to;if ((--in[y]) <= 0) {Q.push(y);buildDominate(y); //建立支配树}}}
}int idom[N];
void dfsDominate(int x) { //在支配树上搜索idomidom[x] = 1;for (int i = dominate.head[x]; i; i = dominate.edge[i].next) {int y = dominate.edge[i].to;dfsDominate(y);idom[x] += idom[y];}
}
int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= m; i++) {int x, y;scanf("%d%d", &x, &y);G.addEdge(x, y);GF.addEdge(y, x);}dfs(1); // dfs,求出dfs序LengauerTarjan(); //计算半支配点sdomtopSort(); //根据dfs树建立dfs树的反图,并对进行拓扑排序从而建立支配树dfsDominate(0); //在支配树上寻找答案for (int i = 1; i <= n; i++)printf("%d ", idom[i]);printf("\n");return 0;
}
支配树(洛谷-P5180)相关推荐
- 信息学奥赛一本通 1365:FBI树(fbi) | 1928:【04NOIP普及组】FBI树 | 洛谷 P1087 [NOIP2004 普及组] FBI 树
[题目链接] ybt 1365:FBI树(fbi) ybt 1928:[04NOIP普及组]FBI树 洛谷 P1087 [NOIP2004 普及组] FBI 树 [题目考点] 1. 二叉树 [解题思路 ...
- 二分答案——砍树(洛谷 P1873)
题目选自洛谷P1873 分析:如果句子非常低,可以收集到的木材会更多,以至于超过需要的数量.随着砍树高度逐渐增大,获得的木材会逐渐减少.砍树高度增加到一定程度时,收集到的木材就会开始不够用.因此需要找 ...
- 线段树 洛谷 p1531 I hate it(I hate it too)
这里写链接内容 线段树模板 字符串是一个很诡异的问题.... #include<cstdio> #include<iostream> #include<string> ...
- 信息学奥赛一本通 1107:校门外的树 | 1931:【05NOIP普及组】校门外的树 | OpenJudge NOI 1.6 06 | 洛谷 P1047 [NOIP2005 普及组] 校门外的树
[题目链接] ybt 1107:校门外的树 ybt 1931:[05NOIP普及组]校门外的树 OpenJudge NOI 1.6 06:校门外的树 洛谷 P1047 [NOIP2005 普及组] 校 ...
- 【学习小记】支配树【图论】
Preface 给定一个有向图和一个起点 s t st st,我们需要知道起点到某个点的关于必经点的信息. 若起点到点v的所有路径均经过点u,则我们称点u支配点v,显然一个点支配自己本身 顾名思义,支 ...
- 洛谷 深基 第1部分 语言入门 第5章 数组与数据批量存储
P1428 小鱼比可爱 小鱼比可爱 - 洛谷 P1427 小鱼的数字游戏 小鱼的数字游戏 - 洛谷 P5727 [深基5.例3]冰雹猜想 [深基5.例3]冰雹猜想 - 洛谷 P5727 [深基5.例3 ...
- 洛谷 P5727 【深基5.例3】冰雹猜想
C语言基础系列文章 C语言 五种方法输出100以内的素数(质数) 源码 C语言分支结构超基础编程习题整理 详细分析附源码 C语言题解 洛谷P1614 爱与愁的心痛 详细分析源码 C语言题解 P5719 ...
- 洛谷 P2597 灾难(支配树)
题目描述 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生物的阿米巴告 ...
- 【洛谷5284】[十二省联考2019] 字符串问题(后缀树优化建边)
题目: 洛谷 5284 分析: 首先不要问我标题里的「后缀树」是什么,我也不会,瞎写的 -- (传说就是反串后缀自动机的 fa 树?) 前置技能:[知识总结]后缀自动机的构建 首先有一个很 naive ...
最新文章
- pycharm中导入包失败,如何设置外部模块的路径
- jarjar.jar解决jar包版本兼容问题
- Java培训教程之对象的创建与使用
- Day5---D4:合规和审计管理
- 数组对象常用处理方案(算法思路)
- 命令行中只用scala来运行一个spark应用
- PMP读书笔记(第6章)
- .net pdf转图片_在客户端实现PDF转图片
- python init main_python 模块中的 __init__.py __main__.py
- flash spi w25q128 w25q64 w25q32 w25q16 verilog fpga程序代码
- Django order by 高级用法
- 截止失真放大电路_这些基本放大器的知识,你会了吗?
- 怎样能让大腿变细方法 揭秘如何瘦大腿和小腿
- 逻辑函数的简化之图解法(卡诺图法)
- SCAPY官方教程二
- TortoiseGit的使用详解
- 算法实验之线性规划解决配料问题
- 牛客 CMB1 序列找数
- Google优化公司采访的最新Google优化资讯报道
- 腾讯云服务器可用区什么意思?