你需要选一个满足下面两个条件的风铃:
(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;
}
这个题目的空间虽然只有16M,但完全是够得