D. Masha and a Beautiful Tree

题目:给定一个完全二叉树,有n个叶子节点,叶子节点的权值是1 - n的排列。一次操作可以交换一个子树的两个儿子,求最小化交换的操作使得叶子节点上的权值递增。

思路:

我们先考虑什么时候有解,对于一个区间[l, r],他的两个子区间是[l, mid]和[mid + 1, r]。如果有解的话,其中一个区间的最小值一定大于另一个区间的最大值。

我们考虑分治,dfs的过程中分裂。每次分裂之后,观察是否满足有解的条件:扫一遍记录最大值最小值比较即可,然后再判断是否需要交换即可,每个节点被访问的次数是nlogn的,因此不会超时。

代码:

void dfs(int l ,int r){
    if(l == r)return;
    int mid = l + r >> 1;
    if(a[l] > a[r])ans ++;
    int mn1 = 0x3f3f3f3f, mx1 = 0, mn2 = 0x3f3f3f3f, mx2 = 0;
    for(int i = l;i <= mid;i ++)
        mn1 = min(mn1, a[i]),mx1 = max(mx1, a[i]);
    for(int i = mid + 1;i <= r;i ++)
        mn2 = min(mn2, a[i]),mx2 = max(mx2, a[i]);
    if(a[l] > a[r]){
        if(mn1 < mx2)
            ans = 0x3f3f3f3f;
    }else{
        if(mx1 > mn2)
            ans = 0x3f3f3f3f;
    }
    dfs(l, mid),dfs(mid + 1, r);
}


void solve(){
    cin >> n;
    for(int i = 1;i <= n;i ++){
        cin >> a[i];
    }    
    if(n == 1){
        cout << 0 << endl;
        return;
    }
    ans = 0;
    dfs(1, n);
    if(ans >= 0x3f3f3f3f)ans = -1;
    cout << ans << endl;
}

你可能感兴趣的:(算法)