tyvj 创世纪 - 基环树
codevs : 传送门
Description
上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。
每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的
世界元素能够限制它,这样上帝就可以保持对世界的控制。由于那个著名的有关于上帝能不能制造一块连自己
都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找
你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2N) 级别的算法。虽然上帝拥有无限多
的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。
题解
把$A[ i ]$ 当作 $f[ i ]$ 即父节点
dfs找环 + 断环 + 重连
只需找到环上的任意两个点记录即可
找到了$x, y$ , 并且$A_x = y$
断环: 让找到的两个点之间的边断开, 从子节点开始$dp$, 算出投放 $x$时的最大值即 $f[x][1]$
重连: 当然不可能真的重连,只需要让 $x$ 不被投放, 并且在处理$y$时, $y$的子节点无需限制它, 因为已经有$x$在限制了
相当于重连
记得手工栈, 不然会RE
注意一个点组成的环需要一些特判,不然会WA
代码
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
#define rd read()
#define rep(i,a,b) for(register int i = (a); i <= (b); ++i)
#define per(i,a,b) for(register int i = (a); i >= (b); --i)
#define R register
using namespace std; const int N = 1e6 + 1e3; int n, m, fa[N], vis[N];
int f[N][], pos1, pos2, eg;
int tot, head[N]; struct edge {
int to, nxt;
}e[N << ]; int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar()) if( c== '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} void add(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
} int lev;
int st_x[N];
int st_nt[N];
int st_tmp[N]; #define x st_x[lev]
#define nt st_nt[lev]
#define tmp st_tmp[lev] void find_cir(int u) {
st_x[] = u;
lev = ;
start:;
vis[x] = ;
nt = fa[x];
if(vis[nt]) {
pos1 = x; pos2 = nt;
}
else {
st_x[lev + ] = nt;
lev++;
goto start;
}
end:;
if((--lev)) goto end;
} int st_i[N]; #define i st_i[lev] void dp(int u) {
st_x[] = u;
lev = ;
start:;
tmp = ;
f[x][] = f[x][] = ;
vis[x] = ;
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(nt == pos1) continue;
st_x[lev + ] = nt;
lev++;
goto start;
end:; f[x][] = f[x][] + max(f[nt][], f[nt][]);
tmp += max(f[nt][], f[nt][]);
}
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(nt == pos1) continue;
f[x][] = max(f[x][], + tmp - max(f[nt][], f[nt][]) + f[nt][]);
}
if(--lev) goto end;
} void dp2(int u) {
st_x[] = u;
lev = ;
start:;
tmp = ;
f[x][] = f[x][] = ;
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(nt == pos1) continue;
st_x[lev + ] = nt;
lev++;
goto start;
end:; f[x][] = f[x][] + max(f[nt][], f[nt][]);
if(x == pos2 && pos1 != pos2) f[x][] = f[x][] + max(f[nt][], f[nt][]);
tmp += max(f[nt][], f[nt][]);
}
if(x == pos2 && pos1 != pos2) {
f[x][]++;
if(--lev) goto end;
}
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
f[x][] = max(f[x][], + tmp - max(f[nt][], f[nt][]) + f[nt][]);
}
if(--lev) goto end;
} #undef x
#undef i
#undef nt
#undef tmp int work(int x) {
int maxn = ;
find_cir(x);
dp(pos1);
maxn = f[pos1][];
dp2(pos1);
maxn = max(maxn, f[pos1][]);
return maxn;
} int main()
{
n = rd;
int ans = ;
rep(i, , n) fa[i] = rd, add(fa[i], i);
rep(i, , n) if(!vis[i]) ans += work(i);
printf("%d\n", ans);
}
tyvj 创世纪 - 基环树的更多相关文章
- BZOJ3037 创世纪[基环树DP]
实际上基环树DP的名字是假的.. 这个限制关系可以看成每个点有一条出边,所以就是一个内向基环树森林. 找出每个基环树的环,然后对于树的部分,做DP,设状态选或不选为$f_{x,0/1}$,则 $f_{ ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- [bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树
创世纪 SZP bzoj-3037/2068 Poi-2004 题目大意:给你n个物品,每个物品可以且仅可以控制一个物品.问:选取一些物品,使得对于任意的一个被选取的物品来讲,都存在一个没有被选取的物 ...
- tyvj1940创世纪——贪心(基环树)
题目:http://www.joyoi.cn/problem/tyvj-1940 基环树的样子,看了书上的讲解,准备写树上DP,然后挂了: #include<iostream> #incl ...
- BZOJ3037 创世纪(基环树DP)
基环树DP,攻的当受的儿子,f表选,g表不选.并查集维护攻受关系.若有环则记录,DP受的后把它当祖宗,再DP攻的. #include <cstdio> #include <iostr ...
- TYVJ 1940 创世纪
Description: 上帝手中有着 N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界.每 种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世 ...
- Poetize4 创世纪
3037: 创世纪 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 123 Solved: 66[Submit][Status] Description ...
- 【BZOJ3037/2068】创世纪/[Poi2004]SZP 树形DP
[BZOJ3037]创世纪 Description applepi手里有一本书<创世纪>,里面记录了这样一个故事……上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放 ...
- CH6401 创世纪
6401 创世纪 0x60「图论」例题 描述 上帝手中有 N(N≤10^6) 种世界元素,每种元素可以限制另外1种元素,把第 i 种世界元素能够限制的那种世界元素记为 A[i].现在,上帝要把它们中的 ...
随机推荐
- CSS 所有样式属性大复习
1.背景与前景 /*背景色,样式表优先级高*/ background-image:url(路径); /*设置背景图片(默认)*/ background-attachment:fixed; ...
- Pandas基础知识(一)
Pandas的主要结构有DataFrame和Series. 生成一个Series对象. 关于部分Series的索引操作. Series也可以通过字典生成. DataFrame是一个表格型的数据,它既有 ...
- Activty左出右进动画
[Activty左出右进动画] public void overridePendingTransition (int enterAnim, int exitAnim) 其中: enterAnim 定义 ...
- django1.10使用本地静态文件
django1.10使用本地静态文件方法 本文介绍的静态文件使用,是指启动web站点后,访问静态资源的用法,实际静态资源地址就是一个个的url 如果没有启动web站点,只是本地调试html页面,那直接 ...
- Numpy:索引与切片
numpy基本的索引和切片 import numpy as np arr = np.array([1,2,3,555,666,888,10]) arr array([ 1, 2, 3, 555, 66 ...
- 九 configparser模块
配置文件如下: # 注释1 ; 注释2 [section1] k1 = v1 k2:v2 user=egon age=18 is_admin=true salary=31 [section2] k1 ...
- preg_match一些问题
<?php$string = 'The quick brown fox jumps over the lazy dog.';$patterns = array();$patterns[0] = ...
- codis
总体架构 192.168.199.223(zookeeper.codis-proxy.codis-dashborad:18080.codis-fe:18090.codis-server) 192.16 ...
- cf-Global Round2-D. Frets On Fire(二分)
题目链接:http://codeforces.com/contest/1119/problem/D 题意:给n(<=1e5)个数s[i],i=1..n,(0<=s[i]<=1e18) ...
- chattr 和 lsattr 命令介绍---案例:修改passwd文件
chattr命令的作用很大,其中一些功能是由Linux内核版本来支持的,如果Linux内核版本低于2.2,那么许多 功能不能实现.同样-D检查压缩文件中的错误的功能,需要2.5.19以上内核才能支持. ...