BZOJ4316 小C的独立集

BZOJ4316 小C的独立集

传送门

BZOJ萎了所以我就放了darkbzoj的链接

题解

考虑求的是仙人掌的最大独立集,我们不需要建出圆方树.还是设\(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\n",max(f[1][0],f[1][1]));
	return 0;
}
posted @ 2020-06-01 15:36  fexuile  阅读(80)  评论(0编辑  收藏  举报