Description:

上帝手中有着 N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每

种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素
能够限制它,这样上帝就可以保持对世界的控制。由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不
但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会 O(2N) 级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。
你需要帮助上帝解决这个问题。

Input:

第一行是一个整数 N,表示世界元素的数目。
  第二行有 N 个整数 A1, A2, …, AN。Ai 表示第 i 个世界元素能够限制的世界元素的编号。

Output:

一个整数,表示最多可以投放的世界元素的数目。

思路:先找环,跑两次树形DP,一次断开,一次重连

然后本机上用光盘里的数据+手动扩栈过了……codevs上因为不能扩栈结果爆栈了……还是我树形DP写得太差了

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N = 1e6 + ;
int n, sz, a[N], dp[N][], dp2[N][], deg[N], fa[N], pre[N], dfn[N], c[N];
vector<int> cir;
bool vis[N]; int head[N], now = ;
struct edges{
int to, next, f;
}edge[N<<];
void add(int u, int v){
edge[++now].to = v, edge[now].next = head[u], edge[now].f = ; head[u] = now;
edge[++now].to = u, edge[now].next = head[v], edge[now].f = ; head[v] = now;
}
int get(int x){
if(x != fa[x]) return fa[x] = get(fa[x]);
return x;
}
void Merge(int x,int y){
x = get(x), y = get(y);
if(x != y) fa[y] = x;
} void fcur(int x){
dfn[x] = ++sz;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(v == pre[x]) continue;
if(dfn[v]){
if(dfn[v] < dfn[x]) continue;
cir.push_back(x); c[x] = ;
for(; x != v; v = pre[v]) c[v] = , cir.push_back(v);
}else pre[v] = x, fcur(v);
}
return ;
}
void dfs2(int x){
dp[x][] = ;
bool flag = ;
int pos = , mn = 1e9;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(edge[i].f) continue;
flag = ;
dfs2(v);
dp[x][] += max(dp[v][], dp[v][]);
if(dp[v][] - dp[v][] < mn){
mn = dp[v][] - dp[v][];
pos = v;
}
}
if(flag) dp[x][]++;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(edge[i].f) continue;
if(v == pos) dp[x][] += dp[v][];
else dp[x][] += max(dp[v][], dp[v][]);
}
return ;
}
void dfs3(int x){
dp2[x][] = ;
bool flag = ;
int pos = , mn = 1e9;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(edge[i].f) continue;
flag = ;
dfs3(v);
dp2[x][] += max(dp2[v][], dp2[v][]);
if(dp2[v][] - dp2[v][] < mn){
mn = dp2[v][] - dp2[v][];
pos = v;
}
}
if(x == a[cir[]]){ //如果找到能强制重连的点
dp2[x][]++;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(edge[i].f) continue;
dp2[x][] += max(dp2[v][], dp2[v][]);
}
return ;
}
if(flag) dp2[x][]++;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(edge[i].f) continue;
if(v == pos) dp2[x][] += dp2[v][];
else dp2[x][] += max(dp2[v][], dp2[v][]);
}
return ;
}
void DP(){
for(int i = head[cir[]]; i; i = edge[i].next)
if(c[edge[i].to] && edge[i].f){ //先断开环上两个点的关系
edge[i ^ ].f = ;
break;
}
dfs2(cir[]);
dfs3(cir[]); //带上强制重连的点DP
dp[cir[]][] = max(dp[cir[]][], dp2[cir[]][]); //更新关系
}
int main(){
int size = << ;
char*p=(char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p) );
// freopen("gen.in","r",stdin);
// freopen("gen.out","w",stdout);
scanf("%d", &n);
for(int i = ; i <= n; i++) fa[i] = i;
for(int i = ; i <= n; i++){
scanf("%d", &a[i]);
add(i, a[i]); Merge(i, a[i]);
}
int ans = ;
for(int i = ; i <= n; i++){ //对于每个联通块找环后DP
int x = get(i);
if(!vis[x]){
cir.clear();
vis[x] = , fcur(i);
// for(int i = 0; i < cir.size(); i++) cout<<cir[i]<<" "; cout<<endl;
DP();
ans += max(dp[cir[]][], dp[cir[]][]);
}
}
printf("%d\n", ans);
return ;
}

在这里插一个基环树找环的代码(适用于无向基环树)

void fcur(int x){
dfn[x] = ++sz;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(v == pre[x]) continue;
if(dfn[v]){
if(dfn[v] < dfn[x]) continue;
cir.push_back(x); c[x] = ;
for(; x != v; v = pre[v]) c[v] = , cir.push_back(v);
}else pre[v] = x, fcur(v);
}
return ;
}

TYVJ 1940 创世纪的更多相关文章

  1. Poetize4 创世纪

    3037: 创世纪 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 123  Solved: 66[Submit][Status] Description ...

  2. 为创世纪图书馆(Library Genesis)作镜像

    简介 Library Genesis的Wikipedia条目中的介绍是: Library Genesis or LibGen is a search engine for articles and b ...

  3. 编程哲学之C#篇:01——创世纪

    我们能否像神一样地创建一个世界? 对于创建世界而言,程序员的创作能力最接近于神--相对于导演,作家,漫画家而言,他们创建的世界(作品)一旦完成,就再也不会变化,创建的角色再也不会成长.而程序员创建的世 ...

  4. 【BZOJ3037/2068】创世纪/[Poi2004]SZP 树形DP

    [BZOJ3037]创世纪 Description applepi手里有一本书<创世纪>,里面记录了这样一个故事……上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放 ...

  5. [bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树

    创世纪 SZP bzoj-3037/2068 Poi-2004 题目大意:给你n个物品,每个物品可以且仅可以控制一个物品.问:选取一些物品,使得对于任意的一个被选取的物品来讲,都存在一个没有被选取的物 ...

  6. CH6401 创世纪

    6401 创世纪 0x60「图论」例题 描述 上帝手中有 N(N≤10^6) 种世界元素,每种元素可以限制另外1种元素,把第 i 种世界元素能够限制的那种世界元素记为 A[i].现在,上帝要把它们中的 ...

  7. 图形学创世纪——写在SIGGRAPH 40年的边上

    40年的边上" title="图形学创世纪--写在SIGGRAPH 40年的边上"> 前言: SIGGRAPH是由ACM SIGGRAPH(美国计算机协会计算机图形 ...

  8. JZOJ 3929. 【NOIP2014模拟11.6】创世纪

    3929. [NOIP2014模拟11.6]创世纪 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description 上帝手 ...

  9. T1创世纪(原创)

    创世纪 这是我的第一道原创题 题解: 这道题的核心算法是:加维度的最短路+贪心 状态:\(dis[i][j][t][a]\)表示在 \(t\) 时,到达 \((i,j)\) ,当前共造\(a\)只&q ...

随机推荐

  1. 内置锁(三)synchronized的几个要注意的对象监视器

    前言    经过前面的两篇文章的介绍,可以清楚知道,synchronized可以用于修饰一个方法 或者 代码块,线程要访问这些临界区代码,则要先获取对应的 对象监视器 ,从而使多个线程互斥访问临界区. ...

  2. 13.mysql基本查询

    1. 给表起个别名:但是,前面的也是需要进行修改的,否则会报错的: select * from s.name from students as s; 2. 为字段起别名 select s,name a ...

  3. menu 一组 只能选择一个

    menu 一组 只能选择一个 将属性表的 groupindex 给一个值,假设你有三个Lang选项 就把这三个 manuitemex.groupindex 都设成同一个编号 (ex: 10) 以及把 ...

  4. Json中相同或者重复记录的值相加组成新的Json

    var data = [ {"Networking": "WiFi", "count_value": "2000"}, ...

  5. MDAC 重新安装

    MDAC 重新安装 c:\windows\inf 下找出mdac.inf 然后点右键->安装

  6. 字符串(string) 的基本操作

    name = "my \tname is alex"  #\t 空格 1. name.capitalize()  #首字母大写 2.name.count('a') # 对字母a计数 ...

  7. struts2,servlet和springmvc的单例多例问题

    struts2,servlet和springmvc的单例多例问题 原创 2017年06月12日 09:59:21 标签: struts2 / servlet / springmvc / 单例 / 多例 ...

  8. CAD2010安装说明

    1. 2. 3. 4. 5. . 提供算号服务(也就是付费才能获得的注册码)... 不会的可以问的撒....

  9. adb设置逍遥游

    . adb设置模拟器属性imei.imsi.手机号.sim卡号2. adb设置充电模式3. 开启|关闭飞行模式4. 获取所有已安装程序apk路径和包名5. adb对指定设备执行指令6. 安装应用7. ...

  10. urllib.parse.urldefrag(url)的解释

    引自https://www.cnblogs.com/ublue/articles/4471210.html 1.URL hash(片段标识符) 任一带#的URL称为片段URL(通常称为URL hash ...