你需要选一个满足下面两个条件的风铃:
(1) 所有的玩具都在同一层(也就是说,每个玩具到天花板之间的杆的个数是一样的)或至多相差一层。
(2) 对于两个相差一层的玩具,左边的玩具比右边的玩具要更靠下一点。
风铃可以按照下面的规则重新排列:任选一根杆,将杆两头的线“交换”。也就是解开一根杆左右两头的线,然后将它们绑到杆的另一头。这个操作不会改变更下面的杆上线的排列顺序。其实看着这个题目我第一反应是平衡树,像splay,fhq之类的可以完成的区间翻转操作,但是这个题目不同的是,他改变两个之后其内部的顺序不变,所以我们可以感性的分析出来反转的顺序对答案没有太多的影响
分析:
由于最大最小相差深度小于等于1,所以可以先dfs一遍,特判一下,0输出0,大于1就是-1(考试时候忘了特判就挂了),对于等于1情况,我们来分析一下什么时候需要翻转:
- 左小右大
- 左有小有大,右大
- 左小,右有小有大
所以,对于这个需要再来一次dfs,用0表示小,1表示大,2表示有小有大,遇到上面三种情况就ans++
完整代码如下:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; #define re register #define gc getchar() #define ll long long #define il inline const int N= 100010; il int read() { re int x(0),f(1); re char ch=gc; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=gc; } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=gc; } return x*f; } int ls[N],rs[N],_max=-1,_min=1e8,deep[N],n,ans,flag=1; void dfs1(int u) { if(ls[u]) { deep[ls[u]]=deep[u]+1; dfs1(ls[u]); } else { _min=min(_min,deep[u]+1); _max=max(_max,deep[u]+1); } if(rs[u]) { deep[rs[u]]=deep[u]+1; dfs1(rs[u]); } else { _min=min(_min,deep[u]+1); _max=max(_max,deep[u]+1); } } namespace SP1 { int x[3][3]= { 0,2,2, 2,1,2, 2,2,2, }; int dfs(int u,int dep) { if(u==-1) { if(dep==_max-1) return 1; return 0; } int a=dfs(ls[u],dep+1); int b=dfs(rs[u],dep+1); if(a==0&&b==1) ++ans; if(a==2&&b==1) ++ans; if(a==0&&b==2) ++ans; if(a==2&&b==2) flag=0; return x[a][b]; } int main() { dfs(1,0); if(!flag) { cout<<-1<<endl; return 0; } cout<<ans<<endl; } }; int main() { n=read(); for(int i=1; i<=n; ++i) ls[i]=read(),rs[i]=read(); dfs1(1); if(_max-_min==1) { SP1::main(); return 0; } if(_max==_min) cout<<0; cout<<-1; return 0; }
很多大佬莫名MLE了,但是这个的空间是足够的,只用了16M