APIO2007 风铃
Posted CaptainLi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(‘ ‘) 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 "); else if(maxn == minn) printf("0 "); else { solve(1,0); flag ? printf("-1 ") : printf("%d ",ans); } return 0; }
以上是关于APIO2007 风铃的主要内容,如果未能解决你的问题,请参考以下文章