【BZOJ】1093: [ZJOI2007]最大半连通子图(tarjan+拓扑序)
http://www.lydsy.com/JudgeOnline/problem.php?id=1093
两个条件综合起来加上求最大的节点数,那么很明显如果是环一定要缩点。
然后再仔细思考下就是求dag的最长路的数目啦。。。
然后wa了。。。
看了题解。。。噗!第一次注意到缩点后会有重边QAQ。。。于是。。
orz orz
然后思考了下怎么处理重边。。。很简单,每个点bfs时记录一下就行了。。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mkpii make_pair<int, int>
#define pdi pair<double, int>
#define mkpdi make_pair<double, int>
#define pli pair<ll, int>
#define mkpli make_pair<ll, int>
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; }
#define rdm(x,i) for(int i=ihead[x]; i; i=e[i].next) const int N=100005, M=1000005;
int TT, FF[N], LL[N], vis[N], s[N], top, scc, p[N], w[N], MD, ans1, ans2, in[N], front, tail;
struct Gr {
int ihead[N], n, cnt;
struct dat { int next, to; }e[M];
void add(int u, int v) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; ++in[v]; }
void dfs(int x) {
FF[x]=LL[x]=++TT; vis[x]=1; s[++top]=x;
rdm(x, i) {
int y=e[i].to;
if(!FF[y]) {
dfs(y);
LL[x]=min(LL[x], LL[y]);
}
else if(vis[y]) LL[x]=min(LL[x], FF[y]);
}
if(FF[x]==LL[x]) {
++scc;
int y;
do {
y=s[top--];
vis[y]=0;
p[y]=scc;
w[scc]++;
} while(x!=y);
}
}
void tarjan() {
for1(i, 1, n) if(!FF[i]) dfs(i);
}
void bfs() {
int *d=FF, *f=LL, *q=s;
for1(i, 1, n) d[i]=f[i]=vis[i]=0;
front=tail=0;
for1(i, 1, n) if(!in[i]) q[tail++]=i, d[i]=w[i], f[i]=1;
while(front!=tail) {
int u=q[front++]; if(front==N) front=0;
rdm(u, i) {
int v=e[i].to;
if(!(--in[v])) { q[tail++]=v; if(tail==N) tail=0; }
if(vis[v]) continue;
if(d[v]==d[u]+w[v]) {
f[v]=(f[v]+f[u])%MD;
}
else if(d[v]<d[u]+w[v]) {
d[v]=d[u]+w[v];
f[v]=f[u];
}
vis[v]=1;
}
rdm(u, i) vis[e[i].to]=0;
}
ans1=-1;
for1(i, 1, n) ans1=max(ans1, d[i]);
for1(i, 1, n) if(ans1==d[i]) ans2=(ans2+f[i])%MD;
}
}G, g;
void build() {
for1(i, 1, g.n) in[i]=0;
G.n=scc;
for1(x, 1, g.n) for(int i=g.ihead[x]; i; i=g.e[i].next) if(p[x]!=p[g.e[i].to]) G.add(p[x], p[g.e[i].to]);
} int main() {
read(g.n);
int m=getint(); read(MD);
for1(i, 1, m) { int u=getint(), v=getint(); g.add(u, v); }
g.tarjan();
build();
G.bfs();
printf("%d\n%d\n", ans1, ans2);
return 0;
}
Description
Input
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。
Output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
Sample Input
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
HINT
对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。
Source
【BZOJ】1093: [ZJOI2007]最大半连通子图(tarjan+拓扑序)的更多相关文章
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
- BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点
Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图, 并求出方案数. ...
- BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)
题目大意 题目是图片形式的,就简要说下题意算了 一个有向图 G=(V, E) 称为半连通的(Semi-Connected),如果满足图中任意两点 u v,存在一条从 u 到 v 的路径或者从 v 到 ...
- BZOJ 1093 [ZJOI2007]最大半连通子图
1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1986 Solved: 802[Submit][St ...
- bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)
1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2286 Solved: 897[Submit][St ...
- 【刷题】BZOJ 1093 [ZJOI2007]最大半连通子图
Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到 ...
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- bzoj 1093: [ZJOI2007]最大半连通子图【tarjan+拓扑排序+dp】
先tarjan缩成DAG,然后答案就变成了最长链,dp的同时计数即可 就是题面太唬人了,没反应过来 #include<iostream> #include<cstdio> #i ...
- bzoj 1093 [ZJOI2007]最大半连通子图——缩点+拓扑
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1093 缩点+拓扑,更新长度的时候维护方案数. 结果没想到处理缩点后的重边,这样的话方案数会算 ...
- Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)
P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...
随机推荐
- Google开源单元測试框架Google Test:VS2012 配置
由题目可知,Google Test(简称gtest)是Google公布的一个开源C/C++測试框架,被应用于多个开源项目及Google内部项目中,包括Chrome浏览器.LLVM编译器架构.Proto ...
- pdf+iphone+wechat
可能很多人要问,为啥标题取这个名字. 因为今天在这个上面踩了太多坑.. 我们的需求其实很简单.做一个页面,把pdf文档嵌进去,在线显示. 如此需求,放在PC上chrome浏览器,一个embed标签就搞 ...
- 【LeetCode】111. Minimum Depth of Binary Tree (2 solutions)
Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum depth is the n ...
- WebForm 页面ajax 请求后台页面 方法
function ReturnOperation(InventoryID) { //入库 接口 if (confirm('你确认?')) { $.ajax({ type: "post&quo ...
- HDU 1695 GCD(容斥定理)
GCD Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- 什么是Coded UI
什么是Coded UI Coded UI Test是Visual Studio 2010对于Testing Project(测试工程)提供的关于UI自动化测试的框架,支持Win32,Web,WPF等U ...
- Mysql 数据库数值类型详解
MySQL 支持所有标准SQL 中的数值类型,其中包括严格数值类型(INTEGER.SMALLINT.DECIMAL 和NUMERIC),以及近似数值数据类型(FLOAT.REAL 和DOUBLE P ...
- Spring IOC和AOP 基础
1 spring中注入资源是通过描述来实现的,在 spring 中是通过注解或者 XML 描述.spring 中IOC 注入方式有三种 1)构造方法注入 2)setter 注入 3)接口注入 1.1) ...
- ACdream 1084 寒假安排(阶乘素因子分解)
题目链接:传送门 分析: 求A(n,m)转化成k进制以后末尾0的个数.对k素因子分解,第i个因子为fac[i], 第i个因子的指数为num[i],然后再对n的对A(n,m)进行素因子分解,设cou ...
- Linux下UTF-8和GB2312互相转换的函数
#include<iconv.h> #include <stdio.h> #include<iconv.h>using namespace std; int utf ...