zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    第四次课堂作业
    12周课后作业
    12周上机(5.21)
    11周周五课后作业
    11周上机作业(5.14)
    第十周(5.7)上机
    第九周4.30上机作业
    第八周周五课后作业
    4.23 第八周上机作业
    4.17课后作业
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/10469347.html
Copyright © 2011-2022 走看看