[HNOI/AHOI2018]毒瘤

[Luogu4426] [LOJ2496]

题解

#include<cstdio>
#include<cstring>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=1e5+5;
const int MAXM=2e5+25;
const int MAXX=15;
const int mod=998244353;

int f[MAXN][2],p[MAXN][2];bool b[MAXN][2];
int dfn[MAXN],size[MAXN],eu[MAXN],ev[MAXN];
bool mark[MAXN],vis[MAXN];
int n,m,dft,Xcnt,ans;

inline int add(int x,int y){x+=y;return x>mod?x-mod:x;}
inline int mul(LL x,int y){x*=y;return x>mod?x%mod:x;}

struct Node{
    int x,y;
    inline Node(){}
    inline Node(int _x,int _y){x=_x,y=_y;}
    inline friend Node operator + (Node a,Node b){return Node(add(a.x,b.x),add(a.y,b.y));}
    inline friend Node operator * (Node a,int b){return Node(mul(a.x,b),mul(a.y,b));}
}k[MAXN][2];

struct Edge{int v,next;}e[MAXM];
int first[MAXN],Ecnt=0;
inline void Add_edge(int u,int v){
    e[++Ecnt]=(Edge){v,first[u]};
    first[u]=Ecnt;
}

struct EXedge{int v,next;Node a,b;}E[MAXM];
int First[MAXN],ECNT=0;
inline void ADD_EDGE(int u,int v,Node a,Node b){
    E[++ECNT]=(EXedge){v,First[u],a,b};
    First[u]=ECNT;
}

inline void dfs1(int u,int pre){
    dfn[u]=++dft;
    for(int i=first[u],v=e[i].v;i;v=e[i=e[i].next].v){
        if(v==pre) continue;
        if(!dfn[v]){
            dfs1(v,u);
            size[u]+=size[v];
        }
        /*else if(dfn[u]<dfn[v]){
            eu[++Xcnt]=u,ev[Xcnt]=v;
            mark[u]=mark[v]=1;
            //printf("%d-%d\n",u,v);
        }*/
        else{
            mark[u]=1;//mark[u]是必须即时更新的 
            if(dfn[u]<dfn[v]) eu[++Xcnt]=u,ev[Xcnt]=v;
        }
    }
    mark[u]|=size[u]>=2;
    size[u]=size[u]||mark[u];
}

inline int dfs2(int u){
    vis[u]=true;
    p[u][0]=p[u][1]=1;
    int pos=0,w;
    for(int i=first[u];i;i=e[i].next){
        int v=e[i].v;
        if(vis[v]) continue;
        w=dfs2(v);
        if(!w){
            p[u][1]=1ll*p[u][1]*p[v][0]%mod;//没有关键点:直接按普通的更新 
            p[u][0]=1ll*p[u][0]*(p[v][0]+p[v][1])%mod;
        }
        else if(mark[u]) ADD_EDGE(u,w,k[v][0]+k[v][1],k[v][0]);
        else k[u][1]=k[v][0],k[u][0]=k[v][0]+k[v][1],pos=w;///
    }
    if(mark[u]) k[u][0]={1,0},k[u][1]={0,1},pos=u;///
    else k[u][0]=k[u][0]*p[u][0],k[u][1]=k[u][1]*p[u][1];///
    return pos;
}

inline void dp(int u){
    //f[u][0]=b[u][0]*p[u][0];//这样写也是错的 
    //f[u][1]=b[u][1]*p[u][1];
    f[u][0]=(b[u][1]^1)*p[u][0];//强制选了另一边,这一边就不能选 
    f[u][1]=(b[u][0]^1)*p[u][1];
    for(int i=First[u];i;i=E[i].next){
        int v=E[i].v;
        dp(v);
        f[u][0]=mul(f[u][0],add(mul(E[i].a.x,f[v][0]),mul(E[i].a.y,f[v][1])));//用处理好了的系数直接相乘 
        f[u][1]=mul(f[u][1],add(mul(E[i].b.x,f[v][0]),mul(E[i].b.y,f[v][1])));
    }
}

int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        Add_edge(x,y);
        Add_edge(y,x);
    }
    dfs1(1,0);mark[1]=1;//根节点作为很多对的lca,必须标记 
    dfs2(1);
    for(int i=0;i<=((1<<Xcnt)-1);i++){
        for(int j=1;j<=Xcnt;j++){
            if(i&(1<<(j-1))) b[eu[j]][1]=b[ev[j]][0]=1;// (1,0) 或者 (0,_) 
            else b[eu[j]][0]=1;
        }
        dp(1);
        ans=add(ans,add(f[1][0],f[1][1]));
        for(int j=1;j<=Xcnt;j++){
            if(i&(1<<(j-1))) b[eu[j]][1]=b[ev[j]][0]=0;
            else b[eu[j]][0]=0;
        }
    }
    printf("%d\n",ans);
}
上一篇:[HNOI/AHOI2018]排列


下一篇:HNOI 2017 礼物