タイトル
近年のZ国が土地の砂漠化プログラムを抑制することが検討されてきました。砂漠の多くは広大な国でZ領土、。干ばつの砂漠は、捨て、唯一の悪魔のサボテンは、この環境の中で生き残ることができます。捜査Z地質探査局の後、彼らは砂漠の地面の状況を得ました。Z米国地質探査庁は愛のCCPC機関である、彼らは景色を見るための方法を記述するためにグラフ理論を使用することを好みます。通信ブロックがあればサボテンエッジであると重量とリングブロックからの通信が存在しないとそれぞれの側は、最も単純なである場合にのみ、データは、サボテン砂漠である通信ブロックの各々で得られましたリングカバー。
Z国が砂漠のエッジの一部を削除することが決定したいくつかの査定後、砂漠は最終的に森林になります。ここでは、森林満足を定義:フォレストは、各通信ブロックは木であり、ツリーはポイント数がマイナス側通信ブロックに等しいです。今、砂漠が含まれているn個の点を考えると、あなたは全体の要件を満たすために砂漠の国の多くの種類、1つのZのリハビリテーションプログラムを見つけます。異なる二つの溶液を場合と異なるシナリオのエッジセットは省略している場合のみ。答えは大きいかもしれないので、998 244 353剰余後の最終的な出力をお答えください。
サンプル:
INPUT:
3 3
1 2
2 3
1 3。
出力:
7
INPUT:
3 3
1 2
2 3
1 3。
出力:
6 6
1 2
2 3
3 1
2 4
4 5
5 2
出力:
49
問題の意味
無向グラフでは(ブロックは、通信を複数有していてもよい)、及びリングからの重いエッジは、各エッジは、最も単純なリングに存在しないことを確実にします。要件:この図(各エッジ点の通信量は、+ 1の数に等しい)どのように多くの種類のプログラムの森へ。
思考
各単純環、辺の数をmとし、プログラム2の数をM -1、単純な複数のリングは、乗算の原理を使用する必要がある場合に限り、最終的に二重リングによって得られた単純なものだけでなく、考えることができ一方的な必要性は2で結果を乗算する場合は一方的な問題(2線)、(2例、このエッジを削除し、このエッジを取り除くしません)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 300005
#define maxm 1000005
#define INF 2147483647123456789
#define mod 998244353
#define IOS ios::sync_with_stdio(false)
int n,m;
struct Edge
{
int st, en;
Edge() {}
Edge(ll a, ll b)
{
st = a, en = b;
}
};
struct node
{
int to,next;
} G[maxm];
int head[maxn],num;
void add(ll from,ll to)
{
G[++num].next=head[from];
G[num].to=to;
head[from]=num;
}
stack <Edge> palm; //保存路径
vector <Edge> block[maxn]; //同一个点双的边保存在一起
int dfn[maxn], low[maxn];
int ind, T; //ind为点双的数量,T为时间
void tarjan(int u, int pre)
{
dfn[u] = low[u] = ++T;
for (int i = head[u]; i != -1; i = G[i].next)
{
int v = G[i].to;
if (!dfn[v])
{
palm.push(Edge(u, v));
tarjan(v, u);
if (low[u]>low[v]) low[u] = low[v];
if (dfn[u] <= low[v])
{
for (Edge temp; !palm.empty(); )
{
temp = palm.top();
if (dfn[temp.st]<dfn[v]) break;
block[ind].push_back(temp), palm.pop();
}
block[ind++].push_back(Edge(u, v));
palm.pop();
}
}
else if (v != pre && dfn[v]<dfn[u])
{
palm.push(Edge(u, v));
if (low[u]>dfn[v]) low[u] = dfn[v];
}
}
}
ll QuickPow(ll x,ll N)
{
ll res = x;
ll ans = 1;
while(N)
{
if(N&1)
{
ans = ans * res%mod;
}
res = res*res%mod;
N = N>>1;
}
return ans%mod;
}
void init()
{
memset(head,-1,sizeof(head));
num=0;
ind=0,T=0;
}
int main()
{
IOS;
cin>>n>>m;
init();
for(int i=1; i<=m; i++)
{
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i,i);
ll ans=1;
for(ll i=0; i<ind; i++)
{
//cout<<"b "<<block[i].size()<<"\n";
if(block[i].size()>1)
{
ll t=block[i].size();
t=QuickPow(2,t)-1;
t=(t+mod)%mod;
ans*=t;
ans%=mod;
}
else if(block[i].size()==1)
{
ans*=2;
ans%=mod;
}
}
cout<<ans<<"\n";
return 0;
}