zoukankan      html  css  js  c++  java
  • P3521 [POI2011]ROT-Tree Rotations(线段树合并)

    一句话题意(不用我改了.....):给一棵n(1≤n≤200000个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。

    ......这题输入很神烦呐。。。

    给你一棵二叉树的dfs序(考场上没发现2333),只有叶子结点有值,然后求逆序对大小

    在考场上,建树建了好久,然后暴力暴了好久,然后得到了0分的好成绩呢(我真棒)

    正解其实也不难想(但是当时不会权值线段树)

    题解:

    其实很简单,想想:对于一层的逆序对,数量是一定的。也就是说,无论怎么转当前子树,对上一层的逆序对数量是没有影响的。

    挺好理解的但是还是上张图吧:

    对于第二层来说,无论左边的2,3怎么改变,相对于右边4,1或1,4的逆序对个数始终不会改变。

    这个性质吼啊

    于是我们只需要求块内的最小逆序对个数就行了。

    然后再考虑怎么求逆序对个数。

    首先,权值线段树是一个桶,而且下标是有序的(废话)

    然后,两课权值线段树在本题中是等价的,也就是说,左右要合并的线段树,除了维护的区间&&存储元素不一样,是满足可并线段树的条件的。

    所以,对于一个区间,逆序对只需要比较左区间的右半边(桶中)数量*右区间的左半边就行了,

    然后再比较swap之后的,贪心地取下去,合并下去就行了。

    .....语言表述有问题,看一下这一小段代码:

    ans1+=(ll )t[t[l].rs].sum*t[t[r].ls].sum;
    ans2+=(ll )t[t[l].ls].sum*t[t[r].rs].sum;

    就这样,比较然后加小的,最后就是总答案了。

    tips:真正明白了指针的好处,好好用啊,但是得注意一下,因为指针是直接改值,有些值不能改的话,得用一个中间变量记录。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=210000;
    #define ll long long
    struct tree
    {
        int ls,rs,sum;
    }t[maxn*30];
    ll ans=0,ans1=0,ans2=0;
    int n,pos;
    int cnt=0;
    void insert(int &x,int l,int r)
    {
        if(!x)
        {
            x=++cnt;
        }
        t[x].sum++;
        if(l==r)
        {
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)
        {
            insert(t[x].ls,l,mid);
        }
        else
        {
            insert(t[x].rs,mid+1,r);
        }
    }
    void merge(int &l,int r)//直接指针合并,比原来的要好写
    {
        if(!l||!r)
        {
            l=l+r;
            return ;
        }
        t[l].sum+=t[r].sum;
        ans1+=(ll )t[t[l].rs].sum*t[t[r].ls].sum;
        ans2+=(ll )t[t[l].ls].sum*t[t[r].rs].sum;
        merge(t[l].ls,t[r].ls);
        merge(t[l].rs,t[r].rs);    
    }
    int work(int &x)
    {
        int T,ls,rs;
        x=0;
        cin>>T;
        if(!T)
        {
            work(ls);
            work(rs);
            ans1=ans2=0;
            x=ls;//指针,得用中间变量存储
            merge(x,rs);
            ans+=min(ans1,ans2);
        }
        else
        {
            pos=T;
            insert(x,1,n);
        }
    }
    int main()
    {
        scanf("%d",&n);
        int t=0;
        work(t);
        printf("%lld",ans);
        return 0;
    }

    (完)

  • 相关阅读:
    WEB开发者必备的7个JavaScript函数
    json分别算出元素的个数和最多的元素
    jquery 对 Json 的各种遍历
    判断图片是否加载完成
    obj转换成数组
    用JavaScript获取页面上被选中的文字的技巧
    PAT 1088 三人行(20 分)(暴力破解+流程分析)
    PAT 1087 有多少不同的值(20)(STL-set代码)
    PAT 1086 就不告诉你(15 )(代码)
    PAT 1087 有多少不同的值(20)(STL—set)
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11774785.html
Copyright © 2011-2022 走看看