ZJOI2008 骑士 基环树

Posted frank-king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJOI2008 骑士 基环树相关的知识,希望对你有一定的参考价值。

ZJOI2008 骑士

 

题意见链接。。。

 

本题较为经典,值得一做。基环外向树练手好题。

如果不考虑环的情况,则就是普通树形DP,f[i][0/1] 表示这个点取或不取。

对于此题一棵树只能出现一个环,我们任意删去环上的一条边,即可转环为树。

对于 (u,v)

1:u 不取,则以 u 为根DP。

2:v 不取,则以 v 为根DP。

不需要考虑两个点的分别情况,DP的时候考虑在内。

 

判环我用并查集。

 

贴代码:

 

技术分享图片
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 int n,m,cnt;
 5 const int N=1000005;
 6 int fa[N],to[N<<1],nxt[N<<1],hea[N],ra[N],rb[N];
 7 ll f[N],g[N],v[N],ans;
 8 inline int getf(int x)
 9 {
10     return fa[x]==x?x:fa[x]=getf(fa[x]);
11 }
12 inline void dfs(int x,int fat)
13 {
14     f[x]=v[x],g[x]=0;
15     for (int i=hea[x]; i; i=nxt[i])
16     {
17         int y=to[i];
18         if (y==fat) continue;
19         dfs(y,x);
20         g[x]+=max(f[y],g[y]);
21         f[x]+=g[y];
22     }
23 }
24 inline void add(int x,int y)
25 {
26     to[++cnt]=y,nxt[cnt]=hea[x],hea[x]=cnt;
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     for (int i=1; i<=n; ++i) fa[i]=i;
32     memset(hea,-1,sizeof(hea));
33     int b;
34     for (int i=1; i<=n; ++i)
35     {
36         scanf("%lld%d",&v[i],&b);
37         if (getf(i)!=getf(b))
38         {
39             add(i,b); add(b,i);
40             fa[fa[i]]=fa[b];
41         }
42         else ra[++m]=i,rb[m]=b;
43     }
44     ll t;
45     for (int i=1; i<=m; ++i)
46     {
47         dfs(ra[i],0); t=g[ra[i]];
48         dfs(rb[i],0); t=max(t,g[rb[i]]);
49         ans+=t;
50     }
51     printf("%lld
",ans);
52     return 0;
53 }
View Code

 

 

 

 

 

fighting fighting fighting

 

以上是关于ZJOI2008 骑士 基环树的主要内容,如果未能解决你的问题,请参考以下文章

基环树/树形DPBZOJ1040-[ZJOI2008]骑士

[ZJOI2008] 骑士

[ZJOI2008]骑士(基环树,树形dp)

bzoj1040: [ZJOI2008]骑士(基环树+树形dp)

BZOJ 1040: [ZJOI2008]骑士(基环树dp)

ZJOI2008骑士(Bzoj1040)——树形DP(基环树)