BZOJ4316 仙人掌DP
https://www.lydsy.com/JudgeOnline/problem.php?id=4316
没有环就是傻逼树形DP
对于环的部分可以tarjan求出
再对环上做类似于BZOJ1040的DP
断掉环的最后一条边,找到环顶和环底,
强制选择环顶不选择环底和选择环底不选择环顶.
#include<cstdio> #include<algorithm> #include<cstring> #define rep(i,s,t) for(register int i=s;i<=t;++i) #define _rep(i,s,t) for(register int i=s;i>=t;--i) #define Rep(i,s,t) for(register int i=s;i<t;++i) #define go(x) for(register int e=las[x];e;e=nxt[e]) #define re register #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define gi(x) read(x) #define gii(x,y) read(x),read(y) #define giii(x,y,z) read(x),read(y),read(z) #define ms(f,x) memset(f,x,sizeof f) namespace IO{ #define gc getchar() #define pc(x) putchar(x) template<typename T>inline void read(T &x){ x=0;int f=1;char ch=gc;while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gc;} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;x*=f;return; } template<typename T>inline void write(T x=0){ T wr[51];wr[0]=0;if(x<0)pc('-'),x=-x;if(!x)pc(48); while(x)wr[++wr[0]]=x%10,x/=10;while(wr[0])pc(48+wr[wr[0]--]);return; } } using IO::read; using IO::write; typedef long long ll; typedef double db; using namespace std; const int N=2e5+11,inf=1<<30; int n,m,x,y,tot,dfc; int a[N],nxt[N],las[N],to[N],dfn[N],low[N],fa[N]; int f[N][2],g[N][2],p[N][2]; inline void add(int x,int y){ nxt[++tot]=las[x],las[x]=tot,to[tot]=y; } inline void solve(int rt,int x){ re int tot=0;a[++tot]=x; for(re int i=x;i!=rt;i=fa[i]) a[++tot]=fa[i]; g[x][0]=f[x][0],g[x][1]=-inf; rep(i,2,tot) g[a[i]][0]=f[a[i]][0], g[a[i]][0]+=max(g[a[i-1]][0],g[a[i-1]][1]), g[a[i]][1]=f[a[i]][1], g[a[i]][1]+=g[a[i-1]][0]; p[rt][1]=max(f[rt][1],g[rt][1]), p[rt][0]=max(f[rt][0],g[rt][0]), g[x][0]=f[x][0],g[x][1]=f[x][1]; rep(i,2,tot) g[a[i]][0]=f[a[i]][0], g[a[i]][0]+=max(g[a[i-1]][0],g[a[i-1]][1]), g[a[i]][1]=f[a[i]][1], g[a[i]][1]+=g[a[i-1]][0]; p[rt][0]=max(f[rt][0],g[rt][0]), f[rt][0]=p[rt][0],f[rt][1]=p[rt][1]; } inline void dfs(int x,int anc){ dfn[x]=low[x]=++dfc,f[x][1]=1; go(x){ re int v=to[e]; if(!dfn[v]){ fa[v]=x, dfs(v,x), low[x]=min(low[x],low[v]); if(low[v]>dfn[x]) f[x][0]+=max(f[v][0],f[v][1]), f[x][1]+=f[v][0]; } else low[x]=min(low[x],dfn[v]); } go(x){ re int v=to[e]; if(anc!=v&&fa[v]!=x&&dfn[x]<dfn[v]) solve(x,v); } } int main(){ gii(n,m); while(m--) gii(x,y),add(x,y),add(y,x); dfs(1,0); printf("%d",max(f[1][0],f[1][1])); return 0; }