首页 > 代码库 > BZOJ 1040: [ZJOI2008]骑士 [DP 环套树]

BZOJ 1040: [ZJOI2008]骑士 [DP 环套树]

传送门

题意:环套树的最大权独立集


一开始想处理出外向树树形$DP$然后找到环再做个环形$DP$

然后看了看别人的题解其实只要断开环做两遍树形$DP$就行了...有道理!

然后洛谷时限再次不科学,卡常失败$SAD$

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int N=1e6+5;inline int read(){    char c=getchar();int x=0,f=1;    while(c<0||c>9){if(c==-)f=-1;c=getchar();}    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}    return x*f;}int n,val[N];struct edge{    int v,ne;}e[N<<1];int h[N],cnt=1;inline void ins(int u,int v){    cnt++;    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;    cnt++;    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;}int a,b;bool vis[N],del[N<<1];void dfs(int u,int fa){    vis[u]=1;    for(int i=h[u];i;i=e[i].ne)         if(e[i].v!=fa){            if(vis[e[i].v]) a=u,b=e[i].v,del[i]=del[i^1]=1;            else dfs(e[i].v,u);        }}ll f[N][2],ans;void dp(int u,int fa){    f[u][1]=val[u];f[u][0]=0;    for(int i=h[u];i;i=e[i].ne)        if(!del[i]&&e[i].v!=fa){            dp(e[i].v,u);            f[u][1]+=f[e[i].v][0];            f[u][0]+=max(f[e[i].v][0],f[e[i].v][1]);        }}int main(){    freopen("in","r",stdin);    n=read();    for(int i=1;i<=n;i++) val[i]=read(),ins(i,read());    for(int i=1;i<=n;i++) if(!vis[i]){        dfs(i,0);        dp(a,0);        ll _=f[a][0];        dp(b,0);        ans+=max(_,f[b][0]);    }    printf("%lld",ans);}

 

BZOJ 1040: [ZJOI2008]骑士 [DP 环套树]