嘘~ 正在从服务器偷取页面 . . .

洛谷P2272 [ZJOI2007]最大半连通子图 题解


洛谷P2272 [ZJOI2007]最大半连通子图 题解

题目链接:P2272 [ZJOI2007]最大半连通子图

题意

一个有向图 \(G=\left(V,E\right)\) 称为半连通的,如果满足:\(\forall u,v\in V\),满足 \(u\to v\)\(v\to u\),即对于图中任意两点 \(u,v\),存在一条 \(u\)\(v\) 的有向路径或者从 \(v\)\(u\) 的有向路径。

\(G'=\left(V',E'\right)\) 满足 \(V'\subseteq 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\),表示一条有向边 \(\left(a,b\right)\)。图中的每个点将编号为 \(1,2,3\dots N\),保证输入中同一个\(\left(a,b\right)\)不会出现两次。

输出格式

应包含两行,第一行包含一个整数 \(K\),第二行包含整数 \(C\bmod X\)

数据范围

对于 \(100\%\) 的数据,\(N\le 10^5\)\(M\le 10^6\)\(X\le 10^8\)

通俗地说,\(G\) 的一个导出子图 \(G^{\prime} = (V^{\prime},E^{\prime})\) 是半连通子图,则有 \[ \forall u,v \in V^{\prime} ,~(u,v) \in E^{\prime} \lor (v,u) \in E^{\prime} \] 对于某一个强连通分量,如果有某个点在某个半连通子图中,

则这个强连通分量中的所有点都可以加入,并且显然,满足半连通的性质

因此我们可以先强连通分量缩点一下。

考虑一个DAG(有向无环图),它的半连通子图一定以拓扑序连通

考虑dp。设 \(f_i\) 表示(缩点后)到点 \(i\) 为止的(带权)最大半连通子图的大小。

设连接到点 \(i\) 的集合为 \(N^{+}(i)\) ,记点 \(i\) 对应的强连通分量大小 \(s_i\)\(i\) 的点权,则 \[ f_i = \max_{k \in N^+(i)} \{ f_k\} +s_i \] 最大的 \(f_i\) 就是第一问的答案。

第二问的话,类似于 P2047 [NOI2007] 社交网络 ,在更新 \(f_i\) 的时候维护一个 \(g_i\) 就行了

具体地,在 topo dp 的过程中

  • \(f_u + s_i > f_v\) ,显然 \(u\) 可以更新 \(v\) 的答案,则 \(f_v \gets f_u +s_i,~g_v \gets g_u\)

  • \(f_v = f_u + s_i\) 时,直接 \(g_v \gets g_v + g_u\) 就好了。

当然,事实上我们并不需要跑一遍 topo 排序

因为 Tarjan 缩点后的点的排列顺序是逆拓扑序

逆拓扑序可以考虑 Tarjan 的过程,其实把每个SCC弹出的时候相当于就是在做逆拓扑了

也就是说,我们只要把缩点后的点倒着扫一遍dp就好了

同时,因为这题是计数题,所以我们要判重边,可以用这个来判断

if(used[v] == u) continue;
used[v] = u;
// dp .... 

时间复杂度 \(\mathcal{O}(n + m)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(1e5+15))
#define M ((int)(1e6+15))
bitset<N> ins;
int f[N],g[N],used[N];
int n,m,mod,pos=1,head[N];
int stktop,tim,dfncnt,scnt;
int sz[N],dfn[N],low[N],stk[N],scc[N],top[N];
struct Edge{int u,v,next;} e[M];
void down(int &x,int y) { x > y ? x = y : 0; }
void up(int &x,int y) { x < y ? x = y : 0; }
void add(int &x,int y) { (x += y) >= mod ? x -= mod : 0; }
void addEdge(int u,int v) { e[++pos]={u,v,head[u]}; head[u] = pos; }
void tarjan(int u)
{
    dfn[u] = low[u] = ++tim;
    ins[u]=1; stk[++stktop]=u;
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])
        {
            tarjan(v); down(low[u], low[v]);
        }else if(ins[v]) down(low[u], dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        top[++scnt] = u;
        for(int p=0; p!=u; )
        {
            p = stk[stktop--]; ins[p]=0;
            scc[p]=scnt; ++sz[scnt];
        }
    }
}
void solve()
{
    for(int u=scnt; u; u--)
    {
        if(!f[u]) {f[u] = sz[u]; g[u] = 1;}
        for(int i=head[u]; i; i=e[i].next)
        {
            int v=e[i].v;
            if(used[v] == u) continue;
            used[v] = u;
            if(f[u] + sz[v] > f[v])
            {
                f[v] = f[u] + sz[v]; g[v] = g[u];
            }else if(f[u] + sz[v] == f[v])
                { add(g[v], g[u]); }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m >> mod;
    for(int i=1,u,v; i<=m; i++) { cin >> u >> v; addEdge(u,v); }
    for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i);
    pos=1; for(int i=1; i<=n; i++) head[i] = 0;
    for(int i=2; i<=m+1; i++)
    {
        int u = scc[e[i].u], v = scc[e[i].v];
        if(u != v) addEdge(u,v);
    }
    solve();
    int ans1=0,ans2=0;
    for(int i=1; i<=scnt; i++) up(ans1, f[i]);
    for(int i=1; i<=scnt; i++) if(f[i] == ans1) add(ans2, g[i]);
    cout << ans1 << '\n' << ans2 << '\n';
    return 0;
}

这码风变成这样全都赖 Roundgod 和 yhx(雾

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/lydsy1093%3Blg2272.html

[2] https://xiaofulll.blog.luogu.org/solution-p2272


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录