zoukankan      html  css  js  c++  java
  • [bzoj2212][Poi2011]Tree Rotations

    3702双倍经验。原题链接2212

    现在有一棵二叉树,所有非叶子节点都有两个孩子。在每个叶子节点上有一个权值(有$n$个叶子节点,满足这些权值为$1..n$的一个排列)。可以任意交换每个非叶子节点的左右孩子。
    要求进行一系列交换,使得最终所有叶子节点的权值按照中序遍历写出来,逆序对个数最少。

    一个节点的子树内的交换与其无关,只与它的左右子树内有多少逆序对有关。所以可以贪心,满足交换一个节点的左右儿子后逆序对最少即可。用线段树合并既可维护子树内的权值,还可以在merge操作时直接求出逆序对数。舍我其谁啊。

    两棵线段树合并时,递归的每一层都计算:

    $x$左子树(小于$mid$个数)与$y$右子树(大于$mid$个数)之积,为交换后的逆序对;

    $x$左子树(小于$mid$个数)与$y$右子树(大于$mid$个数)之积,为不交换的逆序对;

    都累加之后取$min$的那个。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=400010;
    inline int read(){
        int r=0,c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        r=r*10+c-'0',c=getchar();
        return r;
    }
    struct Node{
        int L,R,sum;
    }T[N*20];
    int rt[N],sz,n,cnt;
    int ll[N],rr[N],val[N];
    void getTree(int &x){
        x=++cnt;val[x]=read();
        if(val[x])return;
        getTree(ll[x]);
        getTree(rr[x]);
    }
    #define ls T[o].L
    #define rs T[o].R
    #define mid (l+r>>1)
    void pullup(int o){
        T[o].sum=T[ls].sum+T[rs].sum;
    }
    void ins(int &o,int l,int r,int v){
        o=++sz;
        if(l==r){
            T[o].sum=1;return;
        }
        if(v<=mid)ins(ls,l,mid,v);
        else ins(rs,mid+1,r,v);
        pullup(o);
    }
    LL ans,ans1,ans2;
    int merge(int x,int y){
        if(!x)return y;
        if(!y)return x;
        ans1+=1ll*T[T[x].L].sum*T[T[y].R].sum;
        ans2+=1ll*T[T[x].R].sum*T[T[y].L].sum;
        T[x].L=merge(T[x].L,T[y].L);
        T[x].R=merge(T[x].R,T[y].R);
        pullup(x);
        return x;
    }
    void dfs(int u){
        if(val[u])return;
        dfs(ll[u]);dfs(rr[u]);
        ans1=ans2=0;
        rt[u]=merge(rt[ll[u]],rt[rr[u]]);
        ans+=ans1<ans2?ans1:ans2;
    }
    void init(){
        n=read();
        int r;getTree(r);
        for(int i=1;i<=cnt;i++)
        if(val[i])ins(rt[i],1,n,val[i]);
    }
    void solve(){
        dfs(1);
        cout<<ans<<endl;
    }
    int main(){
        init();
        solve();
    }
    
  • 相关阅读:
    Java实现 洛谷 P1060 开心的金明
    (Java实现) 洛谷 P1605 迷宫
    (Java实现) 洛谷 P1605 迷宫
    (Java实现)洛谷 P1093 奖学金
    (Java实现)洛谷 P1093 奖学金
    Java实现 洛谷 P1064 金明的预算方案
    Java实现 洛谷 P1064 金明的预算方案
    (Java实现) 洛谷 P1031 均分纸牌
    QT树莓派交叉编译环开发环境搭建(附多个exe工具下载链接)
    武则天红人对唐睿宗的桃色报复(如此缺少城府,注定了要在宫廷中过早地出局)
  • 原文地址:https://www.cnblogs.com/orzzz/p/8094176.html
Copyright © 2011-2022 走看看