博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[ZJOI2008]骑士
阅读量:5231 次
发布时间:2019-06-14

本文共 2514 字,大约阅读时间需要 8 分钟。

 

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

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

然而并没有什么用。

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

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

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

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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

 

转载于:https://www.cnblogs.com/mrclr/p/9905362.html

你可能感兴趣的文章
Ubuntu 16.04 安裝Docker
查看>>
整理的linux面试运维题
查看>>
sublime 的简单应用1
查看>>
【转载】Android App应用启动分析与优化
查看>>
java连接字符串操作,可用来向sql传值
查看>>
css图形——椭圆
查看>>
linux下svn命令大全
查看>>
[HNOI2007]紧急疏散evacuate
查看>>
Java流程控制——2017.08.01
查看>>
EntityFramework6.X 之Relationship
查看>>
B. Lost Array
查看>>
zoj 3605
查看>>
begin
查看>>
smarty模板使用
查看>>
Clang调试deadcode思路
查看>>
COMP 208, Assignment
查看>>
字符串转为ArrayBuffer的方法
查看>>
启动动画
查看>>
Ubuntu命令的学习——安装vim软件的方法&查找文件
查看>>
php 生成32位随机字符串 用于支付验证 用户注册
查看>>