APIO2007 风铃

传送门

这道题好巧妙啊……

首先根据题目大意可以知道如果有风铃的深度差值大于1的话那么肯定是不合法的,风铃的深度就可以被看成高的和低的(雾)。

然后,我们要进行交换,但是交换其实并不会改变一个节点所在的子树,也就是说,你不可能把某一个子树从树里面分裂出来再放回去,所以,如果一个节点的左右两棵子树内全都又有高风铃,又有低风铃,那么肯定是无法交换完成的。

否则的话,一共有三种情况需要我们交换:

1.左边全都是深度低的,右边全都是深度高的

2.左边全是深度低的,右边深度高低的都有

3.左边深度高低的都有,右边全是深度高的。

因为我们是递归返回的时候从下向上进行交换,所以我们可以保证在某一层进行交换的时候,子树一定是有序的,所以以上三种情况我们每次交换只要交换一次既满足情况。同时我们可以返回的时候特判不合法情况,同时返回下一层情况。我的做法是用0,1,2来表示上面三种情况,直接返回即可。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 100005;
const int INF = 1000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct node
{
    int lc,rc;
}t[M];

int n,ans,maxn = 0,minn = 100000000;
bool flag;

void dfs(int x,int depth)
{
    if(x == -1)
    {
    minn = min(minn,depth),maxn = max(maxn,depth);
    return;
    }
    dfs(t[x].lc,depth+1),dfs(t[x].rc,depth+1);
}

int solve(int x,int depth)
{
    if(x == -1) return (depth == minn) ? 0 : 1;
    int a = solve(t[x].lc,depth+1),b = solve(t[x].rc,depth+1);
    if((a == 0 && b == 1) || (a == 2 && b == 1) || (a == 0 && b == 2)) ans++;
    if(a == 2 || b == 2)
    {
    if(a == 2 && b == 2) flag = 1;
    return 2;
    }
    if(!a && !b) return 0;
    if(a + b == 1) return 2;
    if(a == 1 && b == 1) return 1;
}

int main()
{
    n = read();
    rep(i,1,n) t[i].lc = read(),t[i].rc = read();
    dfs(1,0);
    if(maxn - minn > 1) printf("-1\n");
    else if(maxn == minn) printf("0\n");
    else
    {
    solve(1,0);
    flag ? printf("-1\n") : printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-10-19 07:40  CaptainLi  阅读(198)  评论(0编辑  收藏  举报