题目描述

一个有向图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 ≤100000, 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+拓扑排序+dp

显然,如果原图是一个DAG,那么选择的就是一条链,答案就是最长链;

如果不是呢?Tarjan缩点,然后拓扑排序+dp求带权最长链即可。正确性显然。

需要注意的是缩完点后如果有重边需要只考虑一条的贡献,因为确定了点就确定了边的选择,只有一次转移的机会。

时间复杂度 $O(n+m)$

#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#define N 100010
using namespace std;
queue<int> q;
vector<int> e[N] , v[N];
int p , deep[N] , low[N] , tot , ins[N] , sta[N] , top , bl[N] , si[N] , num , ind[N] , last[N];
struct data
{
int x , y;
data(int a = 0 , int b = 0) {x = a , y = b;}
data operator+(int a) {return data(x + a , y);}
data operator^(data a)
{
if(x > a.x) return *this;
else if(x < a.x) return a;
else return data(x , (y + a.y) % p);
}
}f[N];
void tarjan(int x)
{
vector<int>::iterator i;
deep[x] = low[x] = ++tot , ins[x] = 1 , sta[++top] = x;
for(i = e[x].begin() ; i != e[x].end() ; i ++ )
{
if(!deep[*i]) tarjan(*i) , low[x] = min(low[x] , low[*i]);
else if(ins[*i]) low[x] = min(low[x] , deep[*i]);
}
if(deep[x] == low[x])
{
int t;
num ++ ;
do
{
t = sta[top -- ] , ins[t] = 0;
bl[t] = num , si[num] ++ ;
}while(t != x);
}
}
void solve(int n)
{
vector<int>::iterator i;
data ans;
int x;
for(x = 1 ; x <= n ; x ++ )
for(i = e[x].begin() ; i != e[x].end() ; i ++ )
if(bl[x] != bl[*i])
v[bl[x]].push_back(bl[*i]) , ind[bl[*i]] ++ ;
for(x = 1 ; x <= num ; x ++ )
if(!ind[x])
f[x] = data(si[x] , 1) , q.push(x);
while(!q.empty())
{
x = q.front() , q.pop() , ans = ans ^ f[x];
for(i = v[x].begin() ; i != v[x].end() ; i ++ )
{
if(last[*i] != x) last[*i] = x , f[*i] = f[*i] ^ (f[x] + si[*i]);
ind[*i] -- ;
if(!ind[*i]) q.push(*i);
}
}
printf("%d\n%d\n" , ans.x , ans.y);
}
inline char nc()
{
static char buf[100000] , *p1 , *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
int ret = 0; char ch = nc();
while(!isdigit(ch)) ch = nc();
while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
return ret;
}
int main()
{
int n = read() , m = read() , i , x , y;
p = read();
for(i = 1 ; i <= m ; i ++ ) x = read() , y = read() , e[x].push_back(y);
for(i = 1 ; i <= n ; i ++ )
if(!deep[i])
tarjan(i);
solve(n);
return 0;
}

【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp的更多相关文章

  1. BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)

    题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...

  2. bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划

    一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...

  3. BZOJ1093 ZJOI2007最大半连通子图(缩点+dp)

    发现所谓半连通子图就是缩点后的一条链之后就是个模板题了.注意缩点后的重边.写了1h+真是没什么救了. #include<iostream> #include<cstdio> # ...

  4. BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )

    WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...

  5. Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)

    P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...

  6. bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)

    Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...

  7. 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

    思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...

  8. [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)

    传送门 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向 ...

  9. BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】

    题目 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G ...

随机推荐

  1. 20154327 EXP8 Web基础

    基础问题回答 (1)什么是表单? 表单:表单在网页中主要负责数据采集功能.一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法. 表单域:包 ...

  2. 不搭建git服务器对git仓库进行局域网内共享多人合作开发项目

    有时候在一个临时局域网内没有搭建git服务器,但是又想多人开发一个项目,此时只要每个人电脑安装有git客户端,参考一下方法即可尝试建一个本地化的远程仓库进行多人开发工作. 远程仓库通常只是一个裸仓库( ...

  3. Python破解压缩包密码问题

    所用知识 1. Pool 进程池 2. try...except 异常处理 3.枚举的方式 4.生成器的运用 逻辑关系 通过生成假密码去碰撞!捕获异常,一直碰撞,直到生成的密码与压缩包建立的密码对应, ...

  4. Redis系列六 Redis事务

    Redis事务 1.介绍 在Redis事务中可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞. 2.事务的作用 一个队列中, ...

  5. 虚拟机安装win7 64位-完美解决-费元星

    安装虚拟机是为了安装一个oracle ,在本机安装 ,本机会卡死,不是每次启动电脑都用oralce,而且有时候服务是关不干净的,所以安装在虚拟机里,需要的时候在开启,特做此记录! 费元星版权Q[971 ...

  6. VIM第七版

    ZZ:退出并保存 e!:退回到上次保存时的样子 cw:修改单词(自动进入插入模式) cc:修改一整行的内容 cs:修改一个词(自动进入插入模式) .:可以重复上一个命令 J:将下一行内容合并到本行末尾 ...

  7. linux 安装 node.js

    wget http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gztar zxvf node-v0.10.26.tar.gzcd node-v0.10. ...

  8. tpo-09 C1 Advice on a term paper's topic

    第 1 段 1.Listen to a conversation between a student and her professor. 请听一段一名学生和教授讨论的对话. 第 2 段 1.Befo ...

  9. lintcode12 带最小值操作的栈

    实现一个带有取最小值min方法的栈,min方法将返回当前栈中的最小值. 你实现的栈将支持push,pop 和 min 操作,所有操作要求都在O(1)时间内完成. 建一个栈helpStack,用来存放从 ...

  10. Python变量常量及注释

    一.变量命名规则1.有字母.数字.下划线搭配组合而成2.不能以数字开头,更不能全为数字3.不能用Python的关键字4.不要太长5.名字要有意义6.不要用中文7.区分大小写8.采用驼峰体命名(多个单词 ...