【BZOJ 1014】 [ZJOI2008]骑士 树形dp

来源:互联网 发布:长沙学历网络教育报考 编辑:程序博客网 时间:2024/06/05 03:19
n个点n条边,虽然不是一个树但还是很接近了,想象一下如果只有n-1条边的情况那么就可以直接套最大独立子集了,so easy。但是这一道题居然环,先别怕,因为只是多了一条边所以即使构成环那么最多只有一个环,只需要找出来,断掉一条边就是一个树了,然后以这条边两边的节点为根做最大独立子集,规定两个节点均不可选情况下的最大值,最后,注意题目中的可能是一个森林
#include<cstdio>#include<cstring>#include<iostream>#define maxn 1000020#define LL long longusing namespace std;LL n,head[maxn],tot,s,t,val[maxn],f[maxn][2],vis[maxn],edg;LL ans;void read(LL& x){char c=getchar();x=0; LL flag=1;for(;c>'9'||c<'0';c=getchar())if(c=='-')flag=-1;for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';x*=flag;}struct edge{LL next,v;}e[maxn*2];void adde(LL a,LL b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}void dfs1(LL u,LL fa){vis[u]=1;for(LL v,i=head[u];i!=-1;i=e[i].next ){v=e[i].v;if(v==fa)continue;if(vis[v])s=v,t=u,edg=i;else dfs1(v,u);} } void dfs2(LL u,LL fa){f[u][0]=0,f[u][1]=val[u];for(LL v,i=head[u];i!=-1;i=e[i].next){v=e[i].v;if(v==fa||i==edg||(i^1)==edg)continue;dfs2(v,u);f[u][0]+=max(f[v][0],f[v][1]);f[u][1]+=f[v][0];}}int main(){read(n);memset(head,-1,sizeof(head));for(LL a,i=1;i<=n;i++){read(val[i]),read(a);adde(i,a),adde(a,i);}LL x;for(LL i=1;i<=n;i++){if(!vis[i]){dfs1(i,i);dfs2(s,s);x=f[s][0];dfs2(t,t);ans+=max(x,f[t][0]);}}printf("%lld",ans);return 0;}


0 0
原创粉丝点击