• [bzoj2212]Tree Rotations(线段树合并)


    解题关键:线段树合并模板题。线段树合并的题目一般都是权值线段树,因为结构相同,求逆序对时,遍历权值线段树的过程就是遍历所有mid的过程,所有能求出所有逆序对。

    #include<iostream>
    #include<cstdio>
    #define ll long long
    using namespace std;
    int n,sz,seg;
    ll ans,cnt1,cnt2;
    int v[400005],l[400005],r[400005],root[400005];
    int sum[4000005],ls[4000005],rs[4000005];
    //动态开点线段树
    //int new_node(){ return ++sz; }
    
    void readtree(int x){
        scanf("%d",&v[x]);
        if(!v[x]){
            l[x]=++sz;
            readtree(l[x]);
            r[x]=++sz;
            readtree(r[x]);
        }
    }
    
    void pushup(int k){
        sum[k]=sum[ls[k]]+sum[rs[k]];
    }
    
    void build(int &k,int l,int r,int val){
        if(!k)k=++seg;
        if(l==r){sum[k]=1;return;}
        int mid=(l+r)>>1;
        if(val<=mid)build(ls[k],l,mid,val);
        else build(rs[k],mid+1,r,val);
        pushup(k);
    }
    
    int merge(int x,int y){
        if(!x)return y;
        if(!y)return x;
        cnt1+=(ll)sum[rs[x]]*sum[ls[y]];
        cnt2+=(ll)sum[ls[x]]*sum[rs[y]];
        ls[x]=merge(ls[x],ls[y]);
        rs[x]=merge(rs[x],rs[y]);
        pushup(x);
        return x;
    }
    void solve(int x){
        if(!x)return;
        solve(l[x]);
        solve(r[x]);
        if(!v[x]){
            cnt1=cnt2=0;
            root[x]=merge(root[l[x]],root[r[x]]);
            ans+=min(cnt1,cnt2);
        }
    }
    int main(){
        scanf("%d",&n);
        ++sz;
        readtree(1);
        for(int i=1;i<=sz;i++)
            if(v[i])build(root[i],1,n,v[i]);
        solve(1);
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    字符串的比较方法---Java
    [模板]二进制枚举
    [唯一分解定理]感谢ZLY讲解
    [数学] 小数点后第n位
    [模板]二维前缀和
    [模板]欧拉函数及其应用
    [51nod] 1024 矩阵中不重复的元素
    Codeforces Round #521 (Div. 3) D. Cutting Out
    [差分] [POJ] 3276 Face The Right Way
    Educational Codeforces Round 54 (Rated for Div. 2) C. Meme Problem
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/10469347.html
Copyright © 2020-2023  润新知