BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】
题目
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G’=(V’,E’)满足V’?V,E’是E中所有跟V’有关的边,
则称G’是G的一个导出子图。若G’是G的导出子图,且G’半连通,则称G’为G的半连通子图。若G’是G所有半连通子图
中包含节点数最多的,则称G’是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。
输入格式
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
00000, M ≤1000000;对于100%的数据, X ≤10^8
输出格式
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
输入样例
6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
输出样例
3
3
题解
一开始被题目吓到了,仔细读题才知道原来就是一个tarjan缩点
最大半连通,其实就是诱导子图中,每对点至少能从其中一个到达另一个。
强联通分量里的点相互到达,缩点。
缩完后是一个DAG图,最大的所求图就是最长的路径了【只有同一条路径长的点满足要求】
要注意的就是统计时要防止由于缩点后新建的重边而重复计算,我用了一个vis数组表示当前点最后被哪个点访问过
具体看代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
using namespace std;
const int maxn = 100005,maxm = 1000005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int N,M,P,h[maxn],ne = 0,head[maxn],nedge = 0;
struct EDGE{int to,nxt;}ed[maxm],edge[maxm];
inline void build(int u,int v){ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;}
inline void add(int u,int v){edge[nedge] = (EDGE){v,head[u]}; head[u] = nedge++;}
int Scc[maxn],scci = 0,st[maxn],top = 0,low[maxn],dfn[maxn],cnt = 0,Siz[maxn];
void dfs(int u){
dfn[u] = low[u] = ++cnt;
st[++top] = u; int to;
Redge(u){
if (!dfn[to = ed[k].to]) dfs(to);
if (dfn[to] && !Scc[to]) low[u] = min(low[u],low[to]);
}
if (dfn[u] == low[u]){
scci++;
do {Scc[st[top]] = scci; Siz[scci]++;}while (st[top--] != u);
}
}
void tarjan(){REP(i,N) if (!dfn[i]) dfs(i);}
queue<int> q;
int f[maxn],g[maxn],inde[maxn],vis[maxn];
void solve(){
memset(head,-1,sizeof(head));
int u,to;
REP(i,N){
u = Scc[i];
Redge(i) if (Scc[to = ed[k].to] != u) add(u,Scc[to]),inde[Scc[to]]++;
}
REP(i,scci) if (!inde[i]) q.push(i),g[i] = 1;
while (!q.empty()){
u = q.front(); q.pop();
f[u] += Siz[u];
for (int k = head[u]; k != -1; k = edge[k].nxt){
if (!(--inde[to = edge[k].to])) q.push(to);
if (vis[to] != u){
vis[to] = u;
if (f[to] < f[u]) f[to] = f[u],g[to] = g[u];
else if (f[to] == f[u]) g[to] = (g[to] + g[u]) % P;
}
}
}
int ans = 0,gmax = -1;
REP(i,scci)
if (f[i] > gmax) {ans = g[i]; gmax = f[i];}
else if (f[i] == gmax) ans = (ans + g[i]) % P;
printf("%d\n%d\n",gmax,ans);
}
int main(){
memset(h,-1,sizeof(h));
N = RD(); M = RD(); P = RD(); int a,b;
while (M--) a = RD(),b = RD(),build(a,b);
tarjan();
solve();
return 0;
}
BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】的更多相关文章
- bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...
- BZOJ1093 ZJOI2007最大半连通子图(缩点+dp)
发现所谓半连通子图就是缩点后的一条链之后就是个模板题了.注意缩点后的重边.写了1h+真是没什么救了. #include<iostream> #include<cstdio> # ...
- [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
传送门 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向 ...
- BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)
题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...
- LG2272/BZOJ1093 「ZJOI2007」最大半连通子图 Tarjan缩点+DAG求最长链
问题描述 LG2272 BZOJ1093 题解 观察半联通的定义,发现图中的一些结点,构成的链一定是一个半联通子图. 此时存在的环可能会干扰求解,于是\(\mathrm{Tarjan}\)缩点. 于是 ...
- [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...
- BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点
Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图, 并求出方案数. ...
- 2018.11.06 bzoj1093: [ZJOI2007]最大半连通子图(缩点+拓扑排序)
传送门 先将原图缩点,缩掉之后的点权就是连通块大小. 然后用拓扑排序统计最长链数就行了. 自己yyyyyy了一下一个好一点的统计方法. 把所有缩了之后的点都连向一个虚点. 然后再跑拓扑,这样最后虚点的 ...
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
随机推荐
- ECSHOP和SHOPEX快递单号查询中通插件V8.6专版
发布ECSHOP说明: ECSHOP快递物流单号查询插件特色 本ECSHOP快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅 ...
- 静态栈抽象数据类型stack实现
#include<stdio.h> #include<stdbool.h> #include<stdlib.h> #define MAX_STACK_SIZE 10 ...
- 多线程编程以及socket编程_Linux程序设计4chapter15
看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建 ...
- go学习笔记-Data类型(Arrays, Slices and Maps)
Data类型(Arrays, Slices and Maps) array array就是数组,定义方式如下: var arr [n]type 在[n]type中,n表示数组的长度,type表示存储元 ...
- [Cracking the Coding Interview] 4.5 Validate BST
Implement a function to check if a binary tree is a binary search tree. 这道题很经典,让我们判断一棵树是不是二叉查找树.但是首先 ...
- 20145202马超 实验二《Java面向对象程序设计》实验报告
实验二 Java面向对象程序设计 实验内容 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握UML建模 4.熟悉S.O.L.I.D原则 5.了解设计模式 实验 ...
- xssbypass小记
简单整理下bypass的一些点 标签外 如果是标签之外 又有htmlspecialchars函数的点 就别想了 在标签外同时能xss但是有长度限制 如果是储存型可以利用多个点 然后构造<scri ...
- SPOJ SUBLEX
SUBLEX - Lexicographical Substring Search 链接 题意 求第k小的子串.相同的算一个. 分析 建立后缀自动机,在后缀自动机上从一个点经过trans,到另一个点, ...
- C#获取网络图片
简单获取图片 string url = zhi_txt.Text;//图片地址 string dizhi = lujing.Text;//图片下载后保存路径及图片名称要写在一块 WebClient w ...
- Java日志(一):log4j与.properties配置文件
日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录,在Apache网站jakarta.apache.org/log4j可以免费下载到Log4j ...