BZOJ4316 小C的独立集
传送门
题解
考虑求的是仙人掌的最大独立集,我们不需要建出圆方树.还是设(f_{u,0/1})表示(u)点选/不选在(u)子树内的最大独立集.
- 对于圆点之间的连边,考虑直接转移.
- 对于方点,等于是一个环,这个环上面的转移等于是钦定(u)选什么,然后把环遍历一遍.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<set>
#include<map>
using namespace std;
#define mp make_pair
#define ll long long
#define re register
typedef pair<int,int> pii;
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
{
int f=1,sum=0;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=200010;
int n,m,front[N],cnt,f[N][2],fa[N],low[N],dfn[N],Time;
struct node{int to,nxt;}e[N<<1];
void Add(int u,int v){e[++cnt]=(node){v,front[u]};front[u]=cnt;}
void solve(int u,int v)
{
int s0,s1,f0=0,f1=0;
for(int i=v;i!=u;i=fa[i])
{
s0=f0+f[i][0];s1=f1+f[i][1];
f0=max(s0,s1);f1=s0;
}
f[u][0]+=f0;
f0=0,f1=-1e9;
for(int i=v;i!=u;i=fa[i])
{
s0=f0+f[i][0];s1=f1+f[i][1];
f0=max(s0,s1);f1=s0;
}
f[u][1]+=f1;
}
void dfs(int u,int ff)
{
dfn[u]=low[u]=++Time;fa[u]=ff;f[u][0]=0;f[u][1]=1;
for(int i=front[u];i;i=e[i].nxt)
{
int v=e[i].to;if(v==ff)continue;
if(!dfn[v]){dfs(v,u);low[u]=min(low[u],low[v]);}
else low[u]=min(low[u],dfn[v]);
if(dfn[u]<low[v])
{
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
}
}
for(int i=front[u];i;i=e[i].nxt)
{
int v=e[i].to;if(v==ff)continue;
if(fa[v]!=u&&dfn[u]<dfn[v])solve(u,v);
}
}
int main()
{
n=gi();m=gi();
for(int i=1;i<=m;i++)
{
int u=gi(),v=gi();
Add(u,v);Add(v,u);
}
dfs(1,0);
printf("%d
",max(f[1][0],f[1][1]));
return 0;
}