码迷,mamicode.com
首页 > 其他好文 > 详细

[ZJOI2008]骑士

时间:2018-11-04 21:20:32      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:说明   open   hide   name   ons   memset   std   nbsp   char   

嘟嘟嘟

 

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

 

[ZJOI2008]骑士

标签:说明   open   hide   name   ons   memset   std   nbsp   char   

原文地址:https://www.cnblogs.com/mrclr/p/9905362.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!