Forest Program【2019CCPC 秦皇岛 F】【点双联通分量】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_41730082/article/details/102468803

HDU 6736


Problem Description

The kingdom of Z is fighting against desertification these years since there are plenty of deserts in its wide and huge territory. The deserts are too arid to have rainfall or human habitation, and the only creatures that can live inside the deserts are the cactuses. In this problem, a cactus in desert can be represented by a cactus in graph theory.
In graph theory, a cactus is a connected undirected graph with no self-loops and no multi-edges, and each edge can only be in at most one simple cycle. While a tree in graph theory is a connected undirected acyclic graph. So here comes the idea: just remove some edges in these cactuses so that the remaining connected components all become trees. After that, the deserts will become forests, which can halt desertification fundamentally.
Now given an undirected graph with n vertices and m edges satisfying that all connected components are cactuses, you should determine the number of schemes to remove edges in the graph so that the remaining connected components are all trees. Print the answer modulo 998244353.
Two schemes are considered to be different if and only if the sets of removed edges in two schemes are different.

Input

The first line contains two non-negative integers n, m (1 ≤ n ≤ 300 000, 0 ≤ m ≤ 500 000), denoting the number of vertices and the number of edges in the given graph.
Next m lines each contains two positive integers u, v (1 ≤ u, v ≤ n, u = v), denoting that vertices u and v are connected by an undirected edge.
It is guaranteed that each connected component in input graph is a cactus.

Output

Output a single line containing a non-negative integer, denoting the answer modulo 998244353.


  挺不错的一道题,最近也是刚写了几道点双的题目,所以写起来倒是得心应手。

  我们把u->v找到“dfn[u] == low[v]”这样点进行处理成一个环,他们是在一个集合中的,此时不能退栈到u,退到v即可。然后就是这样的点双思想直接走下去即可。

思维上,可以参考圆方树

  然后,我们知道这是一张仙人掌的图,保证了连通性,把所有的缩点之后,那么会有一个新得到的“方点”(圆方树),然后对方点的链接结点的个数进行存储下来,然后我们直接ans = \cdot (2^{siz_{1}} - 1) \cdot (2^{siz_{2}} - 1) \cdot \cdots \cdot (2^{(restM)})就是我们所需要的答案了。

具体详看代码了:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 6e5 + 7, maxE = 1e6 + 7;
const ll mod = 998244353;
ll fast_mi(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
int N, M, tot;
struct Eddge
{
    int head[maxN], cnt, to[maxE], nex[maxE];
    Eddge()
    {
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    inline void addEddge(int u, int v)
    {
        nex[cnt] = head[u]; to[cnt] = v;
        head[u] = cnt++;
    }
    inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
    inline void init()
    {
        cnt = 0;
        for(int i=1; i<=N; i++) head[i] = -1;
    }
}E;
int dfn[maxN], low[maxN], Stap[maxN], Stop, tim, dis[maxN], siz[maxN];
inline void work(int u, int v)
{
    tot++; siz[tot] = dis[Stap[Stop]] - dis[u] + 1;
    int t;
    do
    {
        t = Stap[Stop--];
    }while(t != v);
}
void Tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tim;
    Stap[++Stop] = u;
    for(int i=E.head[u], v; ~i; i=E.nex[i])
    {
        v = E.to[i];
        if(v == fa) continue;
        if(!dfn[v])
        {
            dis[v] = dis[u] + 1;
            Tarjan(v, u);
            if(dfn[u] < low[v]) { Stop--; continue; }
            else if(dfn[u] == low[v])
            {
                work(u, v);
            }
            low[u] = min(low[u], low[v]);
        }
        else
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
}
inline void init()
{
    tim = Stop = 0;
    tot = N;
    E.init();
    for(int i=1; i<=N; i++) dfn[i] = 0;
    dis[1] = 0;
}
int main()
{
    while(scanf("%d%d", &N, &M)!=EOF)
    {
        init();
        for(int i=1, u, v; i<=M; i++)
        {
            scanf("%d%d", &u, &v);
            E._add(u, v);
        }
        Tarjan(1, 0);
        ll ans = 1;
        for(int i=N + 1; i<=tot; i++)
        {
            ans = (ans * ( ( fast_mi(2, siz[i]) - 1 + mod) % mod) ) % mod;
            M -= siz[i];
        }
        if(M) ans = (ans * fast_mi(2, M)) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/102468803
今日推荐