[APIO2007] 风铃

题目链接

可能是个树上 DP?指针真好玩 23333。

首先对于所有玩具如果有深度差超过 1 的就是无解(在这里贡献 WA * 3),所以 dfs 一遍记录深度是有必要的……

然后如果有一个点的两颗子树中都含有最小、最大深度,那么这种情况也是无解,可以令同时含有两种深度的子树 tag = 1。

然后考虑最少交换次数,对于每一个节点的左右子树,三种情况需要交换:

 1. 左边全是小深度的,右边全是大深度的

 2. 左边全是小深度的,右边大小深度都有

 3. 左边大小深度都有,右边全是大深度的

root->cnt = left_child->cnt + right_child->cnt + 本次是否需要交换(0 or 1)。

所以代码判的挺多的……

 1 #include <queue>
 2 #include <cstdio>
 3 #include <cctype>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 const int maxn = 200000 + 10;
10 int n, in_deg[maxn], maxx, minn, ans, node_num;
11 
12 struct Node {
13   int deep, cnt, tag, type;
14   Node *lchild, *rchild;
15 
16   Node() { type = cnt = deep = 0, lchild = rchild = NULL; }
17   ~Node() {};
18 } node[maxn], *p_root;
19 
20 inline int read() {
21   register char ch = 0; register int w = 0, x = 0;
22   while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar();
23   while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
24   return w ? -x : x;
25 }
26 
27 inline void Set_deep(Node *x) {
28   if( x->lchild != NULL ) x->lchild->deep = x->deep + 1, Set_deep(x->lchild);
29   if( x->rchild != NULL ) x->rchild->deep = x->deep + 1, Set_deep(x->rchild);
30 }
31 
32 inline void Deep_fs(Node *x) {
33   if( x->lchild == NULL && x->rchild == NULL ) return ;
34   if( x->lchild != NULL ) Deep_fs(x->lchild);
35   if( x->rchild != NULL ) Deep_fs(x->rchild);
36   if( x->lchild->tag && x->rchild->tag ) ans = -1;
37   if( x->lchild->type ^ x->rchild->type ) x->tag = 1;
38   else if( x->lchild->tag | x->rchild->tag ) x->tag = 1;
39   else if( x->lchild->deep != x->rchild->deep ) x->tag = 1;
40   x->cnt = x->lchild->cnt + x->rchild->cnt;
41   x->deep = max(x->lchild->deep, x->rchild->deep);
42   if( x->lchild->tag ^ x->rchild->tag ) {
43     if( x->lchild->tag && x->lchild->deep == x->rchild->deep ) ++x->cnt;
44     if( x->rchild->tag && x->lchild->deep < x->rchild->deep ) ++x->cnt;
45   } else if( x->lchild->deep < x->rchild->deep ) ++x->cnt;
46 }
47 
48 int main(int argc, const char *argv[])
49 {
50   freopen("..\\nanjolno.in", "r", stdin);
51   freopen("..\\nanjolno.out", "w", stdout);
52 
53   scanf("%d", &n), node_num = n, minn = 2e9;
54   for(int l, r, i = 1; i <= n; ++i) {
55     l = read(), r = read();
56     if( l == -1 ) node[++node_num].type = 1, node[i].lchild = &node[node_num];
57     else node[i].lchild = &node[l], ++in_deg[l];
58     if( r == -1 ) node[++node_num].type = 1, node[i].rchild = &node[node_num];
59     else node[i].rchild = &node[r], ++in_deg[r];
60   }
61   for(int i = 1; i <= n; ++i) if( in_deg[i] == 0 ) p_root = &node[i];
62   p_root->deep = 1, Set_deep(p_root);
63   for(int i = 1; i <= node_num; ++i) if( node[i].type ) {
64     maxx = max(maxx, node[i].deep), minn = min(minn, node[i].deep);
65   }
66   if( maxx - minn > 1 ) puts("-1");
67   else Deep_fs(p_root), printf("%d\n", ans == -1 ? ans : p_root->cnt);
68 
69   fclose(stdin), fclose(stdout);
70   return 0;
71 }

 —— “从你慷慨的手里所付予的,我都接受。我别无所求。”
    “是了,是了,我懂得你,谦卑的乞丐,你是乞求一个人的一切所有。”

猜你喜欢

转载自www.cnblogs.com/nanjoqin/p/10081893.html
今日推荐