题解:首先考虑一棵树怎么做,就是树形
d
p
dp
dp,然后我们可以枚举每一条边怎么选,显然有 3 种情况 进一步发现只需要枚举两种,即强制
u
u
u 选
v
v
v 不选,和强制
u
u
u 不选
v
v
v 随意 那么现在的问题就是每次
b
a
n
ban
ban 掉一些点选一些点不选,动态更新根节点的
d
p
dp
dp 值 然后把转移写成矩阵的形式链分治,由于可以除
0
0
0 所以手写了一个用
x
∗
0
y
x*0^y
x∗0y 表示每个数的类 复杂度
O
(
n
+
k
∗
2
k
∗
l
o
g
(
n
)
2
)
O(n+k*2^k*log(n)^2)
O(n+k∗2k∗log(n)2) 被虚树吊打
#include<bits/stdc++.h>#define pb push_back#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch =='-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();return cnt * f;}
cs int N = 1e5 + 50, K = 15;
cs int Mod = 998244353;
int add(int a, int b){return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){return 1ll * a * b % Mod;}
int dec(int a, int b){return a - b < 0 ? a - b + Mod : a - b;}
int ksm(int a, int b){ int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a);return ans;}
void Add(int &a, int b){ a = add(a, b);}
void Mul(int &a, int b){ a = mul(a, b);}
int n, m, k, u[K], v[K];
vector<int> G[N];
int sz[N], son[N], fa[N], dep[N], in[N], top[N], bot[N], sgn;
struct mat{
int a[2][2];
mat(int _x=0, int _y=0){ a[0][0]=a[1][0]=_x; a[0][1]=_y; a[1][1]=0;}
mat operator * (cs mat &A){
mat B;
for(int i=0; i<2; i++) for(int k=0; k<2; k++) if(a[i][k])
for(int j=0; j<2; j++) if(A.a[k][j]) Add(B.a[i][j],mul(a[i][k],A.a[k][j]));return B;}
int vl(){return add(a[0][0],a[0][1]);}};
struct num{
int x,y;
num(){ x = y = 1;}
void operator =(int v){v ? (x=v,y=0):(x=y=1);}
void operator *=(int v){v ? x=mul(x,v): ++y;}
void operator /=(int v){v ? x=mul(x,ksm(v,Mod-2)): --y;}
operator int()cs{return y?0:x;}};
void pre_dfs(int u, int f){
sz[u]= 1;
for(int v: G[u]) if(v ^ f){
fa[v]= u; dep[v]= dep[u]+1; pre_dfs(v,u);
sz[u] += sz[v]; if(sz[son[u]]<sz[v]) son[u]=v;}}
namespace SGT{
cs int N = ::N<<2;
mat vl[N];#define mid ((l+r)>>1)
void pushup(int x){ vl[x]= vl[x<<1|1] * vl[x<<1];}
void modify(int x, int l, int r, int p, mat v){
if(l == r){ vl[x]=v;return;}(p<=mid)?modify(x<<1,l,mid,p,v):modify(x<<1|1,mid+1,r,p,v); pushup(x);}
mat query(int x, int l, int r, int L, int R){
if(L<=l&&r<=R)return vl[x];
if(R<=mid)return query(x<<1,l,mid,L,R);else if(L>mid)return query(x<<1|1,mid+1,r,L,R);elsereturn query(x<<1|1,mid+1,r,L,R)*query(x<<1,l,mid,L,R);}}
int f[N][2]; num coe[N][2];
void dfs(int u, int tp){
top[u]= tp; in[u]=++sgn;
if(son[u]) dfs(son[u],tp), bot[u]=bot[son[u]];else bot[u]=u;
coe[u][0]=1; coe[u][1]=1;
for(int v: G[u]) if(v!=fa[u]&&v!=son[u])
dfs(v,v), coe[u][0]*=add(f[v][0],f[v][1]), coe[u][1]*=f[v][0];
SGT::modify(1,1,n,in[u],mat(coe[u][0],coe[u][1]));
if(son[u]) f[u][0]=mul(coe[u][0],add(f[son[u]][0],f[son[u]][1])), f[u][1]=mul(coe[u][1],f[son[u]][0]);else f[u][0]=f[u][1]=1;}
int state[N];
void upt(int u){
mat now;
while(u){
int tp = fa[top[u]];
if(tp){
now = SGT::query(1,1,n,in[top[u]],in[bot[u]]);
coe[tp][0]/=now.vl(), coe[tp][1]/=now.a[0][0];}
if(state[u]==1) SGT::modify(1,1,n,in[u],mat(coe[u][0],0));else if(state[u]==2) SGT::modify(1,1,n,in[u],mat(0,coe[u][1]));else SGT::modify(1,1,n,in[u],mat(coe[u][0],coe[u][1]));
if(tp){
now = SGT::query(1,1,n,in[top[u]],in[bot[u]]);
coe[tp][0]*=now.vl(), coe[tp][1]*=now.a[0][0];} u = tp;}}
int anc[N];
int find(int x){return x==anc[x]?x:anc[x]=find(anc[x]);}
bool ck(int S){
for(int i=0; i<k; i++) state[u[i]]=state[v[i]]=0;
for(int i=0; i<k; i++){
if(S>>i&1){
if(state[u[i]]==1)returnfalse; state[u[i]]=2;
if(state[v[i]]==2)returnfalse; state[v[i]]=1;}
else{
if(state[u[i]]==2)returnfalse; state[u[i]]=1;}}returntrue;}
int main(){
n = read(), m = read();
for(int i=1; i<=n; i++) anc[i]=i;
for(int i=1,x,y; i<=m; i++){
x=read(), y=read();
if(find(x)^find(y)) G[x].pb(y),G[y].pb(x),anc[find(x)]=find(y);else u[k]=x,v[k++]=y;}
pre_dfs(1,0); dfs(1,1); int as = 0;
for(int S=0; S<(1<<k); S++){
if(!ck(S))continue;
for(int i=0; i<k; i++){
if(S>>i&1) upt(u[i]), upt(v[i]);else upt(u[i]);}
Add(as,SGT::query(1,1,n,in[1],in[bot[1]]).vl());
for(int i=0; i<k; i++) state[u[i]]=state[v[i]]=0;
for(int i=k-1; ~i; i--){
if(S>>i&1) upt(v[i]), upt(u[i]);else upt(u[i]);}} cout << as;return 0;}