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; }
当你意识到,每个上一秒都成为永恒。