bzoj1040(ZJOI2008)骑士——基环树
Posted Narh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1040(ZJOI2008)骑士——基环树相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1040
基环树的模板。
套路就是把环断开,先把一端作为根节点,强制不选;再把另一端作为根节点,强制不选。
人家的这个判断环的方法真好!还顺便没有连上环的那条边,省下了在函数里判断。
别忘了有多棵基环树!
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=1e6+5; int n,m,head[N],xnt,fa[N],rta[N],rtb[N]; ll dp[N][2],a[N],ans; struct Edge{ int next,to; Edge(int n=0,int t=0):next(n),to(t) {} }edge[N<<1]; int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} void add(int a,int b) { edge[++xnt]=Edge(head[a],b);head[a]=xnt; edge[++xnt]=Edge(head[b],a);head[b]=xnt; fa[find(a)]=find(b); } void sol(int cr,int fa) { dp[cr][1]=a[cr];dp[cr][0]=0; for(int i=head[cr],v;i;i=edge[i].next) { v=edge[i].to; if(v==fa)continue; sol(v,cr); dp[cr][0]+=max(dp[v][0],dp[v][1]); dp[cr][1]+=dp[v][0]; } } int main() { scanf("%d",&n);int tmp; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=n;i++) { scanf("%lld%d",&a[i],&tmp); if(find(i)!=find(tmp)) add(i,tmp); else rta[++m]=i,rtb[m]=tmp; } ll c; for(int i=1;i<=m;i++) { sol(rta[i],0);c=dp[rta[i]][0]; sol(rtb[i],0);c=max(c,dp[rtb[i]][0]); ans+=c; } printf("%lld",ans); return 0; }
以上是关于bzoj1040(ZJOI2008)骑士——基环树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1040: [ZJOI2008]骑士(基环树dp)
ZJOI2008骑士(Bzoj1040)——树形DP(基环树)
bzoj1040[ZJOI2008]骑士 并查集+基环树dp