• 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

    代码

      1 #include<cstring>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #define ll long long
      5 #define rd read()
      6 #define rep(i,a,b) for(register int i = (a); i <= (b); ++i)
      7 #define per(i,a,b) for(register int i = (a); i >= (b); --i)
      8 #define R register
      9 using namespace std;
     10 
     11 const int N = 1e6 + 1e3;
     12 
     13 int n, m, fa[N], vis[N];
     14 int f[N][2], pos1, pos2, eg;
     15 int tot, head[N];
     16 
     17 struct edge {
     18     int to, nxt;
     19 }e[N << 1];
     20 
     21 int read() {
     22     int X = 0, p = 1; char c = getchar();
     23     for(; c > '9' || c < '0'; c = getchar()) if( c== '-') p = -1;
     24     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
     25     return X * p;
     26 }
     27 
     28 void add(int u, int v) {
     29     e[++tot].to = v;
     30     e[tot].nxt = head[u];
     31     head[u] = tot;
     32 }
     33 
     34 int lev;
     35 int st_x[N];
     36 int st_nt[N];
     37 int st_tmp[N];
     38 
     39 #define x st_x[lev]
     40 #define nt st_nt[lev]
     41 #define tmp st_tmp[lev]
     42 
     43 void find_cir(int u) {
     44     st_x[1] = u;
     45     lev = 1;
     46 start:;
     47     vis[x] = 1;
     48     nt = fa[x];
     49     if(vis[nt]) {
     50         pos1 = x; pos2 = nt;
     51     }
     52     else {
     53         st_x[lev + 1] = nt;
     54         lev++;
     55         goto start;
     56     }
     57 end:;
     58     if((--lev)) goto end;
     59 }
     60 
     61 
     62 int st_i[N];
     63 
     64 #define i st_i[lev]
     65 
     66 void dp(int u) {
     67     st_x[1] = u;
     68     lev = 1;
     69 start:;
     70     tmp = 0;
     71     f[x][1] = f[x][0] = 0;
     72     vis[x] = 1;
     73     for(i = head[x]; i; i = e[i].nxt) {
     74         nt = e[i].to;
     75         if(nt == pos1) continue;
     76         st_x[lev + 1] = nt;
     77         lev++;
     78         goto start;
     79 end:;
     80 
     81         f[x][0] = f[x][0] + max(f[nt][0], f[nt][1]);
     82         tmp += max(f[nt][1], f[nt][0]);
     83     }
     84     for(i = head[x]; i; i = e[i].nxt) {
     85         nt = e[i].to;
     86         if(nt == pos1) continue;
     87         f[x][1] = max(f[x][1], 1 + tmp - max(f[nt][0], f[nt][1]) + f[nt][0]);
     88     }
     89     if(--lev) goto end;
     90 }
     91 
     92 void dp2(int u) {
     93     st_x[1] = u;
     94     lev = 1;
     95 start:;
     96     tmp = 0;
     97     f[x][1] = f[x][0] = 0;
     98     for(i = head[x]; i; i = e[i].nxt) {
     99         nt = e[i].to;
    100         if(nt == pos1) continue;
    101         st_x[lev + 1] = nt;
    102         lev++;
    103         goto start;
    104 end:;
    105 
    106         f[x][0] = f[x][0] + max(f[nt][0], f[nt][1]);
    107         if(x == pos2 && pos1 != pos2) f[x][1] = f[x][1] + max(f[nt][0], f[nt][1]);
    108         tmp += max(f[nt][1], f[nt][0]);
    109     }
    110     if(x == pos2 && pos1 != pos2) {
    111         f[x][1]++;
    112         if(--lev) goto end;
    113     }    
    114     for(i = head[x]; i; i = e[i].nxt) {
    115         nt = e[i].to;
    116         f[x][1] = max(f[x][1], 1 + tmp - max(f[nt][0], f[nt][1]) + f[nt][0]);
    117     }
    118     if(--lev) goto end;
    119 }
    120 
    121 #undef x
    122 #undef i
    123 #undef nt
    124 #undef tmp
    125 
    126 int work(int x)  {
    127     int maxn = 0;
    128     find_cir(x);
    129     dp(pos1);
    130     maxn = f[pos1][1];
    131     dp2(pos1);
    132     maxn = max(maxn, f[pos1][0]);
    133     return maxn;
    134 }
    135 
    136 int main()
    137 {
    138     n = rd;
    139     int ans = 0;
    140     rep(i, 1, n) fa[i] = rd, add(fa[i], i);
    141     rep(i, 1, n) if(!vis[i]) ans += work(i);
    142     printf("%d
    ", ans);
    143 }
    View Code
  • 相关阅读:
    大数据面试题题库
    IDEA下通过Git实现代码管理
    使用QJM实现HDFS的HA配置
    1、HDFS分布式文件系统
    分析system_call中断处理过程
    由一段代码解析系统调用的原理
    从linux内核代码分析操作系统启动过程
    一个简单的时间片轮转多道程序内核
    从一段代码的汇编看计算机的工作原理
    九度OJ1468
  • 原文地址:https://www.cnblogs.com/cychester/p/9569915.html
Copyright © 2020-2023  润新知