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();
    }
    
  • 相关阅读:
    CentOS Linux下VNC Server远程桌面配置详解
    Java 中的悲观锁和乐观锁的实现
    spring @configuration使用
    MySQL 汉字拼音
    chmod用数字来表示权限的方法
    C语言创建删不掉的目录
    Android小经验
    系统清理——查找大文件
    最全Pycharm教程(42)——Pycharm扩展功能之Emacs外部编辑器
    怎样学习程序
  • 原文地址:https://www.cnblogs.com/orzzz/p/8094176.html
Copyright © 2011-2022 走看看