zoukankan      html  css  js  c++  java
  • [ZJOI2008]骑士

    嘟嘟嘟

    n个点n条边,说明图中存在一个简单环,更准确的说是每一个连通块中存在一个简单环(因为图可能不连通)。

    然后有人给这个玩意起了个名字:基环外向树。

    然而并没有什么用。

    思路很简单:断环为链,就变成了一棵树了。为了防止断开的两端(x, y)同时被选,从x和y分别树形dp一下,然后硬性规定根节点不能选即可。

    树形dp就不说啦,就是没有上司的舞会。

    需要注意的是,找环不仅要记录端点,还要记录断开的边E。然后E和E ^ 1就是断开的边。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 1e6 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 int n, a[maxn];
     38 
     39 struct Edge
     40 {
     41     int nxt, to;
     42 }e[maxn << 1];
     43 int head[maxn], ecnt = -1;
     44 void addEdge(int x, int y)
     45 {
     46     e[++ecnt] = (Edge){head[x], y};
     47     head[x] = ecnt;
     48 }
     49 
     50 int rt1, rt2, E;        //E, E ^ 1:the edge wich is cutted
     51 bool vis[maxn], cir[maxn];
     52 void Find(int now, int _e)
     53 {
     54     vis[now] = cir[now] = 1;
     55     for(int i = head[now], v; i != -1; i = e[i].nxt)
     56     {
     57         v = e[i].to;
     58         if(cir[v] && i != (_e ^ 1))
     59         {
     60             rt1 = now; rt2 = v; E = i;
     61         }
     62         if(!vis[v]) Find(v, i);
     63     }
     64     cir[now] = 0;
     65 }
     66 
     67 ll dp[maxn][2];
     68 void dfs(int now, int f)
     69 {
     70     dp[now][0] = dp[now][1] = 0;
     71     for(int i = head[now], v; i != -1; i = e[i].nxt)
     72     {
     73         v = e[i].to;
     74         if(v == f || i == E || i == (E ^ 1)) continue;
     75         dfs(v, now);
     76         dp[now][1] += dp[v][0];
     77         dp[now][0] += max(dp[v][1], dp[v][0]);
     78     }
     79     dp[now][1] += a[now];
     80 }
     81 
     82 int main()
     83 {
     84     Mem(head, -1);
     85     n = read();
     86     for(int i = 1; i <= n; ++i)
     87     {
     88         a[i] = read(); 
     89         int x = read(); addEdge(i, x); addEdge(x, i);
     90     }
     91     ll ans = 0;
     92     for(int i = 1; i <= n; ++i) if(!vis[i])
     93     {
     94         Find(i, -1);
     95         dfs(rt1, 0);
     96         ll Max = 0;
     97         if(dp[rt1][0] > Max) Max = dp[rt1][0];
     98         dfs(rt2, 0);
     99         if(dp[rt2][0] > Max) Max = dp[rt2][0];
    100         ans += Max;
    101     }
    102     write(ans), enter;
    103     return 0;
    104 }
    View Code
  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/mrclr/p/9905362.html
Copyright © 2011-2022 走看看