1. 程式人生 > >APIO2007 風鈴

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; }