自己 yy 了一个动态 dp 做法,应该是全网唯一用 LCT 写的.    

code: 

#include <bits/stdc++.h>
#define ll long long
#define lson tr[x].ch[0]
#define rson tr[x].ch[1]
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int N=200005;
const ll mod=998244353;
vector<int>EDGE;
int edges=1,n,m,F[N][2];
int hd[N],to[N<<1],nex[N<<1],from[N<<1],mark[N<<1],vis[N],sta[N];
int qpow(int x,int y)
{
    int tmp=1;
    while(y)
    {
        if(y&1)  tmp=1ll*tmp*x%mod;
        x=1ll*x*x%mod, y>>=1;
    }
    return tmp;
}
int INV(int x) { return qpow(x,mod-2); }
void add(int u,int v)
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,from[edges]=u;
}
void dfs(int u,int ff)
{
    vis[u]=1;
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==ff||mark[i])   continue;
        if(vis[v])
        {
            mark[i]=mark[i^1]=1, EDGE.push_back(i);
            continue;
        }
        dfs(v,u);
    }
}
struct Num
{
    int val,cnt;
    Num() { val=cnt=0; }
    void ins(int a)
    {
        val=a,cnt=0;
        if(!val)    val=1,cnt=1;
    }
    Num operator*(Num b) const
    {
        Num re;
        re.val=1ll*val*b.val%mod;
        re.cnt=cnt+b.cnt;
        return re;
    }
    Num operator/(Num b) const
    {
        Num re;
        re.cnt=cnt-b.cnt;
        re.val=1ll*val*INV(b.val)%mod;
        return re;
    }
    int get() { return cnt?0:val; }
}tmp[N][2][2];
struct matrix
{
    int a[2][2];
    matrix() { memset(a,0,sizeof(a)); }
    void I()
    {
        a[0][0]=a[1][1]=1;
        a[0][1]=a[1][0]=0;
    }
    int *operator[](int x) { return a[x]; }
}t[N],po[N];
matrix operator*(matrix a,matrix b)
{
    matrix c;
    for(int i=0;i<2;++i)
    {
        for(int j=0;j<2;++j)
            for(int k=0;k<2;++k)
                c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j]%mod)%mod;
    }
    return c;
}
void cop(int x)
{
    for(int i=0;i<2;++i)
    {
        for(int j=0;j<2;++j)
            t[x][i][j]=tmp[x][i][j].get();
    }
}
struct node
{
    int ch[2],f,rev;
}tr[N];
int get(int x)
{
    return tr[tr[x].f].ch[1]==x;
}
int isrt(int x)
{
    return !(tr[tr[x].f].ch[0]==x||tr[tr[x].f].ch[1]==x);
}
void pushup(int x)
{
    cop(x);
    t[x]=po[x]*t[x];
    if(lson)   t[x]=t[lson]*t[x];
    if(rson)   t[x]=t[x]*t[rson];
}
void rotate(int x)
{
    int old=tr[x].f,fold=tr[old].f,which=get(x);
    if(!isrt(old))     tr[fold].ch[tr[fold].ch[1]==old]=x;
    tr[old].ch[which]=tr[x].ch[which^1],tr[tr[old].ch[which]].f=old;
    tr[x].ch[which^1]=old,tr[old].f=x,tr[x].f=fold;
    pushup(old),pushup(x);
}
void splay(int x)
{
    int u=x,v=0,fa;
    for(sta[++v]=u;!isrt(u);u=tr[u].f)   sta[++v]=tr[u].f;
    for(u=tr[u].f;(fa=tr[x].f)!=u;rotate(x))
    {
        if(tr[fa].f!=u)
        {
            rotate(get(fa)==get(x)?fa:x);
        }
    }
}
void Access(int x)
{
    for(int y=0;x;y=x,x=tr[x].f)
    {
        splay(x);
        if(rson)
        {
            Num a,b;
            a.ins(t[rson][0][0]);
            b.ins(t[rson][0][0]+t[rson][1][0]);
            tmp[x][1][0]=tmp[x][1][0]*a;
            tmp[x][0][0]=tmp[x][0][0]*b;
            tmp[x][0][1]=tmp[x][0][1]*b;
        }
        if(y)
        {
            Num a,b;
            a.ins(t[y][0][0]);
            b.ins(t[y][0][0]+t[y][1][0]);
            tmp[x][1][0]=tmp[x][1][0]/a;
            tmp[x][0][0]=tmp[x][0][0]/b;
            tmp[x][0][1]=tmp[x][0][1]/b;
        }
        rson=y;
        pushup(x);
    }
}
void prepare(int u,int ff)
{
    po[u].I();
    tr[u].f=ff;
    tmp[u][1][1].ins(0);
    tmp[u][0][0].ins(1);
    tmp[u][0][1].ins(1);
    tmp[u][1][0].ins(1);
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==ff||mark[i])     continue;
        prepare(v,u);
        Num a,b;
        a.ins(tmp[v][0][0].get());
        b.ins(tmp[v][0][0].get()+tmp[v][1][0].get());
        tmp[u][0][0]=tmp[u][0][0]*b;
        tmp[u][0][1]=tmp[u][0][1]*b;
        tmp[u][1][0]=tmp[u][1][0]*a;
    }
    pushup(u);
}
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs(1,0);
    prepare(1,0);
    ll ans=0ll;
    int sta=EDGE.size();
    if(sta==0)
    {
        Access(3),splay(3);
        ans=(t[3][0][0]+t[3][1][0])%mod;
    }
    else
    {
        for(i=0;i<(1<<sta);++i)
        {
            for(j=0;j<sta;++j)
            {
                if(i&(1<<j))
                {
                    int u=from[EDGE[j]];
                    int v=to[EDGE[j]];
                    Access(u),splay(u);
                    po[u][0][0]=0;
                    pushup(u);

                    Access(v),splay(v);
                    po[v][1][1]=0;
                    pushup(v);
                }
                else
                {
                    int u=from[EDGE[j]];
                    Access(u),splay(u);
                    po[u][1][1]=0;
                    pushup(u);
                }
            }
            Access(1),splay(1);
            (ans+=(t[1][0][0]+t[1][1][0])%mod)%=mod;
            for(j=0;j<sta;++j)
            {
                if(i&(1<<j))
                {
                    int u=from[EDGE[j]];
                    int v=to[EDGE[j]];
                    Access(u),splay(u);
                    po[u][0][0]=1;
                    pushup(u);
                    Access(v),splay(v);
                    po[v][1][1]=1;
                    pushup(v);
                }
                else
                {
                    int u=from[EDGE[j]];
                    Access(u),splay(u);
                    po[u][1][1]=1;
                    pushup(u);
                }
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

  

12-23 11:30
查看更多