题目描述
https://www.lydsy.com/JudgeOnline/upload/201804/%E6%B9%96%E5%8D%97%E4%B8%80%E8%AF%95%E8%AF%95%E9%A2%98.pdf
题解
大意:给出一张n个点n+x条边的无向连通图,x很小,求出这个图上最大独立集的方案数。
感觉就是NOIP保卫王国那题的加强版吧。
暴力的话,我们可以考虑在图上随便找一颗生成树,然后把非树边连接的点设置为关键点,然后2^x枚举这些点的选择情况,每次做一遍树形dp就好了。
如果做到这里,那么可以自然而然的想到一个优化:虚树。
就是发现在虚树上的非关键点部分的转移相似,所以我们可以预处理出这些东西来。
我们设f[i][0/1]表示i点的所有不包含关键点的子树的答案。
对于关键点到关键点的转移,我们可以设k[i][0/1][0/1]表示关键点i点到i点的第一个关键点祖先的儿子处i点和那个儿子的选择情况的方案数。
这个直接从i点向上跳,边跳边统计答案就可以算出来了。
注意虚树上的LCA点也要标为关键点。
代码
#include#include #include #include #include #include #define N 110009 using namespace std; typedef long long ll; const int mod=998244353; vector<int>vec[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct node{int u,v;}ed[50]; ll k[N][2][2],g[N][2],f[N][2],ans; int tot,head[N],dfn[N],p[19][N],deep[N],a[N],ttt,n,m,st[N],top; bool vis[N],dy1[N],dy0[N],tag[N]; struct edge{int n,to;}e[N<<1]; inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;} inline void add2(int u,int v){tag[u]=1;tag[v]=1;vec[u].push_back(v);}////!!!!!!!!! void dfs(int u,int fa){ dfn[u]=++dfn[0];vis[u]=1; for(int i=1;(1<1][p[i-1][u]]; for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){ int v=e[i].to; if(!vis[v]){deep[v]=deep[u]+1;p[0][v]=u;dfs(v,u);} else{a[++a[0]]=u;a[++a[0]]=v;ed[++ttt]=node{u,v};} } } inline bool cmp(int a,int b){return dfn[a]<dfn[b];} inline int getlca(int a,int b){ if(deep[a]<deep[b])swap(a,b); for(int i=17;i>=0;--i)if(deep[a]-(1<=deep[b])a=p[i][a]; if(a==b)return a; for(int i=17;i>=0;--i)if(p[i][a]!=p[i][b])a=p[i][a],b=p[i][b]; return p[0][a]; } void predp(int u,int jin){ f[u][0]=f[u][1]=1;tag[u]=1; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(p[0][v]!=u||v==jin||tag[v])continue; predp(v,jin); f[u][0]=f[u][0]*(f[v][0]+f[v][1])%mod; f[u][1]=f[u][1]*f[v][0]%mod; } } inline void getnum(int x,int y){ k[x][0][0]=k[x][1][1]=1; for(int i=x;p[0][i]!=y;i=p[0][i]){ predp(p[0][i],i); ll xx=k[x][0][0],yy=k[x][1][0]; k[x][0][0]=f[p[0][i]][0]*(k[x][0][1]+k[x][0][0])%mod; k[x][0][1]=f[p[0][i]][1]*xx%mod; k[x][1][0]=f[p[0][i]][0]*(k[x][1][0]+k[x][1][1])%mod; k[x][1][1]=f[p[0][i]][1]*yy%mod; } } void prework(int u){ for(int i=0;i i){ int v=vec[u][i]; prework(v);getnum(v,u); } f[u][0]=f[u][1]=1; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(p[0][v]!=u||tag[v])continue; predp(v,0); f[u][0]=f[u][0]*(f[v][0]+f[v][1])%mod; f[u][1]=f[u][1]*f[v][0]%mod; } } void dp(int u){ g[u][0]=f[u][0];g[u][1]=f[u][1]; if(dy1[u])g[u][0]=0;if(dy0[u])g[u][1]=0; for(int i=0;i i){ int v=vec[u][i]; dp(v); ll k0=(k[v][0][0]*g[v][0]%mod+k[v][1][0]*g[v][1]%mod)%mod,k1=(k[v][0][1]*g[v][0]%mod+k[v][1][1]*g[v][1]%mod)%mod; g[u][0]=g[u][0]*(k0+k1)%mod;g[u][1]=g[u][1]*k0%mod; } } int main(){ n=rd();m=rd();int u,v; for(int i=1;i<=m;++i){ u=rd();v=rd(); add(u,v);add(v,u); } dfs(1,0);sort(a+1,a+a[0]+1,cmp); a[0]=unique(a+1,a+a[0]+1)-a-1; st[top=1]=1; for(int i=1;i<=a[0];++i){ tag[a[i]]=1; if(a[i]==st[top])continue; int lca=getlca(st[top],a[i]); if(lca==st[top]){st[++top]=a[i];continue;} while(top>1){ int x=st[top],y=st[top-1]; if(dfn[lca]>=dfn[y]){add2(lca,x);top--;break;} add2(y,x);top--; } if(st[top]!=lca)st[++top]=lca; if(st[top]!=a[i])st[++top]=a[i]; } while(top>1)add2(st[top-1],st[top]),top--; prework(1); for(int i=0;i<(1<0]);++i){ for(int j=1;j<=a[0];++j)if(i&(1< 1))dy1[a[j]]=1,dy0[a[j]]=0;else dy0[a[j]]=1,dy1[a[j]]=0; bool tagg=0; for(int j=1;j<=ttt;++j){ int u=ed[j].u,v=ed[j].v; if(dy1[u]&&dy1[v]){tagg=1;break;} } if(tagg)continue; dp(1); (ans+=g[1][0]+g[1][1])%=mod; } cout<<ans; return 0; }