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;
}
BZOJ4316

 

posted @ 2018-05-20 22:17  Stump  阅读(102)  评论(0编辑  收藏