创世纪 BZOJ3037 & [Poi2004]SZP BZOJ2068
2018-05-23 22:27
447 查看
分析:
树形DP中的一种,基环树DP
针对每一个环跑DP,f[i],g[i]分别表示选或者不选,之后我们注意每次遍历的时候,不要重复遍历。
附上代码:
#include <cstdio> #include <algorithm> #include <cmath> #include <iostream> #include <queue> #include <cstring> #include <cstdlib> using namespace std; #define N 1000005 struct node { int to,next; }e[N<<1]; int head ,cnt,f ,g ,fa ,now,n,ra ,rb ; void add(int x,int y) { e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt++; return ; } int find(int x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);} void dfs(int x) { int minn=1<<30; g[x]=0; for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=now)dfs(to1); g[x]+=max(f[to1],g[to1]); minn=min(minn,max(f[to1],g[to1])-g[to1]); } f[x]=g[x]+1-minn; } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n);int cnt=0; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(find(x)!=find(i)) { add(x,i); fa[fa[x]]=fa[i]; }else ra[++cnt]=x,rb[cnt]=i; } int ans=0; for(int i=1;i<=cnt;i++) { dfs(ra[i]);now=ra[i]; dfs(rb[i]); int t=f[rb[i]]; f[ra[i]]=g[ra[i]]+1; dfs(rb[i]);ans+=max(t,g[rb[i]]); } printf("%d\n",ans); return 0; }
相关文章推荐
- [bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树
- 【BZOJ3037/2068】创世纪/[Poi2004]SZP 树形DP
- BZOJ 3037 创世纪
- bzoj3037 创世纪
- [BZOJ1005][HNOI2008]明明的烦恼&&[BZOJ1211][HNOI2004]树的计数【prufer序列】
- BZOJ 2066 [Poi2004]Gra
- [BZOJ2072][POI2004] MOS过桥
- bzoj 2073: [POI2004]PRZ
- 【bzoj2073】【[POI2004]PRZ】位运算枚举子集的特技
- BZOJ_2073_[POI2004]PRZ_状压DP
- bzoj 2067 [Poi2004]SZN 贪心 二分
- [bzoj3037][贪心]创世纪
- BZOJ 2073: [POI2004]PRZ [DP 状压]
- [牛顿法 || 二分] BZOJ 1213 [HNOI2004]高精度开根 & 51Nod 1166 大数开平方
- BZOJ2073: [POI2004]PRZ
- poj 2376 && bzoj 3389: [Usaco2004 Dec]Cleaning Shifts安排值班(贪心)
- 【bzoj 3037】创世纪
- bzoj 4386: [POI2015]Wycieczki 矩阵乘法&倍增
- BZOJ 1208 [HNOI2004] 宠物收养所 题解&代码
- 【BZOJ】【P2073】【POI2004】【PRZ】【题解】【状压DP+枚举子集】