博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj1093 [ZJOI2007]最大半联通子图 缩点 + 拓扑序
阅读量:4926 次
发布时间:2019-06-11

本文共 2512 字,大约阅读时间需要 8 分钟。

最大半联通子图对应缩点后的$DAG$上的最长链

复杂度$O(n + m)$

#include 
#include
#include
using namespace std;extern inline char gc() { static char RR[23456], *S = RR + 23333, *T = RR + 23333; if(S == T) fread(RR, 1, 23333, stdin), S = RR; return *S ++;}inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc(); return p * w; }#define ri register int#define sid 1005000int n, m, id, nid, cnp, mod, top;int pre[sid], nxt[sid], node[sid], cap[sid], vis[sid];int low[sid], dfn[sid], st[sid], ins[sid], cnt[sid], b[sid], deg[sid], q[sid];inline void addedge(int u, int v) { nxt[++ cnp] = cap[u]; cap[u] = cnp; pre[cnp] = u; node[cnp] = v; deg[v] ++;}void tarjan(int o, int fa) { low[o] = dfn[o] = ++ id; st[++ top] = o; ins[o] = 1; #define cur node[i] for(int i = cap[o]; i; i = nxt[i]) { if(!dfn[cur]) tarjan(cur, o), low[o] = min(low[o], low[cur]); else if(ins[cur]) low[o] = min(low[o], dfn[cur]); } if(dfn[o] == low[o]) { int p; ++ nid; do{ p = st[top --]; b[p] = nid; ins[p] = 0; cnt[nid] ++; } while(p != o); }}inline void inc(int &a, int b){ a += b; if(a >= mod) a -= mod; }struct dp { int sz, num; friend void cmax(dp &a, dp b) { if(b.sz > a.sz) a = b; else if(b.sz == a.sz) inc(a.num, b.num); }} f[sid];void top_dp() { int fr = 1, to = 0; for(ri i = 1; i <= nid; i ++) { if(!deg[i]) q[++ to] = i; f[i] = { cnt[i], 1 }; } #define cur node[i] while(fr <= to) { int o = q[fr ++]; for(ri i = cap[o]; i; i = nxt[i]) { deg[cur] --; if(!deg[cur]) q[++ to] = cur; if(vis[cur] == o) continue; cmax(f[cur], (dp){ f[o].sz + cnt[cur], f[o].num } ); vis[cur] = o; } } dp ans = { 0, 0 }; for(ri i = 1; i <= nid; i ++) cmax(ans, f[i]); printf("%d\n%d\n", ans.sz, ans.num);}int main() { n = read(); m = read(); mod = read(); for(ri i = 1; i <= m; i ++) { int u = read(), v = read(); addedge(u, v); } for(ri i = 1; i <= n; i ++) if(!dfn[i]) tarjan(i, 0); memset(cap, 0, (n + 2) << 2); memset(deg, 0, (n + 2) << 2); int cno = cnp; cnp = 0; for(ri i = 1; i <= cno; i ++) if(b[pre[i]] != b[node[i]]) addedge(b[pre[i]], b[node[i]]); top_dp(); return 0;}

 

转载于:https://www.cnblogs.com/reverymoon/p/9649450.html

你可能感兴趣的文章
查询数据占用磁盘大小
查看>>
通用分页(一)
查看>>
前端基础进阶(四):详细图解作用域链与闭包
查看>>
Android的Bitmap和BitmapDrawable类解析-android学习之旅(六十)
查看>>
阿里云服务器CentOS7 vsftp安装、设置及后台端口的设置
查看>>
让webapi支持CORS,可以跨域访问
查看>>
Git的使用-如何将本地项目上传到Github
查看>>
ShellShock 攻击实验
查看>>
如何使多个页面同步使用一个页面模板
查看>>
CentOS下KVM增加磁盘/磁盘扩容/在线扩容
查看>>
前端性能优化总结
查看>>
TCP/IP Protocol Family
查看>>
python 生成器和各种推导式
查看>>
算法导论 练习题 2.3-7
查看>>
linux开机服务自启
查看>>
在Ubuntu下进行MongoDB安装步骤
查看>>
数据结构(C语言版)顺序表相关算法代码实现
查看>>
抛弃强大的TFS ,借助于BugTracker.NET + Visual Source Safe + SourceLink搭建项目开发环境...
查看>>
小工具发布(2008-01-25更新,HTML、URL编解码工具)
查看>>
第三次上机作业
查看>>