Codeforces Round 826 (Div. 3) D. Masha and a Beautiful Tree (分治)

名叫玛莎的女孩在森林里散步时发现了一棵完整的二叉树,树高 n n n ,长度为 m = 2 n m=2n m=2n 的排列组合 p p p

一棵高度为 n n n 的完整二叉树是一棵有根的树,它的每个顶点(叶子除外)都正好有两个子顶点,并且从树根到任何一个叶子的路长度都是 n n n 。下图是 n = 2 n=2 n=2 的完整二叉树。

排列是由 n n n 个不同的整数组成的数组,从 1 1 1 n n n 。例如, [ 2 , 3 , 1 , 5 , 4 ] [ 2,3,1,5,4 ] [2,3,1,5,4] 是一个排列,但是 [ 1 , 2 , 2 ] [ 1,2,2 ] [1,2,2] 不是( 2 2 2 出现了两次), [ 1 , 3 , 4 ] [ 1,3,4 ] [1,3,4] 也不是一个排列 ( n = 3 ( n=3 (n=3 ,但是数组中有 4 ) 4 ) 4)

让我们从左到右枚举这棵树的 m 片叶子。编号为 i 的叶子包含值 pi ( 1≤i≤m )。( 1≤i≤m ).

例如,如果 n=2 , p=[3,1,4,2] ,这棵树就会变成这样:

如果树叶中的值从左到右依次递增,Masha 就会认为这棵树很漂亮。

在一次操作中,Masha 可以选择树中任何一个非叶顶点,交换它的左右子树(及其子树)。

例如,如果 Masha 对上面讨论的树的根进行这一操作,它的形式将如下:

帮助玛莎了解她是否能通过一定数量的操作使一棵树变得美丽。如果可以,那么输出使树变美所需的最少操作数。

输入

第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t ( 1≤t≤10^4 ) t(1t104) —— 测试用例数。

在每个测试用例中,第一行包含一个整数 m ( 1 ≤ m ≤ 262144 ) m ( 1≤m≤262144 ) m(1m262144),该整数是 2 2 2 的幂次,即排列的大小 p p p

第二行包含 m m m 个整数: p 1 , p 2 , … , p m ( 1 ≤ p i ≤ m ) p_1,p_2,…,p_m ( 1≤p_i≤m ) p1,p2,,pm(1pim) —— 排列 p p p

保证所有测试用例中 m m m 的总和不超过 3 ⋅ 1 0 5 3⋅10^5 3105

输出

对于每个测试用例,另起一行打印 Masha 能让树变得漂亮的最小操作数,如果不能,则打印 -1


二叉树由于其性质与分治的思想嵌合较好,故经常两个东西一块考。

对于这道题操作的时候,根据分治的思想,我们就把二叉树每一层都进行一次分段的操作,比如在根节点的时候,我们可以分为左子树和右子树,这时候去看两段的叶节点(p数组)的值,如果左子树的最大值大于了右子树的最大值,那么就需要左右子树进行交换。

然后我们就可以不断重复这个过程,遍历完整个二叉树。

如果最后p数组可以被排序好,那么就说明得到了解,如果没有就输出-1.


CODE:

#include<bits/stdc++.h>
using namespace std;
const int N = 262144 + 10;

int p[N];

int dfs(int l,int r){
    if(l == r)return 0;

    int res = 0;
    int mid = l + r >> 1;
    int maxL = *max_element(p+l,p+mid+1);
    int maxR = *max_element(p+mid+1,p+r+1);


    if(maxL > maxR){
        res++;
        for(int i = l;i <= mid;i++){	//交换左右子树操作
            swap(p[i],p[mid + i - l + 1]);
        }
    }
    return dfs(l,mid) + dfs(mid + 1,r) + res;   //继续搜当前节点的左子树和右子树
}

void solve(){
    int n;cin >> n;
    for(int i = 1;i <= n;i++)cin >> p[i];

    int res = dfs(1,n);

    if(is_sorted(p+1,p+1+n))cout << res << endl;
    else cout << -1 << endl;
}

int main(){
    int T;cin >> T;
    while(T--){
        solve();
    }
    return 0;
}

分治的题目接触较少,思想还未掌握,需要练习。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值