题解:[APIO2007]风铃

你需要选一个满足下面两个条件的风铃:
(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

原文地址:https://www.cnblogs.com/zijinjun/p/10596489.html