• BZOJ 2212: [Poi2011]Tree Rotations(线段树合并)


    传送门

    解题思路

      线段树合并,考虑交换两个子树时,对除这两棵子树外的其余点的逆序对不会造成影响,所以我们只需要贪心的使这两棵子树产生的逆序对最小。而考虑时我们也只需要考虑两棵子树间的逆序对数,不需要考虑每棵子树内部逆序对数,这样就非常好算了,可以线段树合并,合并的同时统计一下交换前和后的逆序对数,然后取个(min)加到答案里。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    
    using namespace std;
    const int N=200005;
    typedef long long LL;
    
    inline int rd(){
        int x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) f=ch=='-'?9:1,ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return f?x:-x;	
    }
    
    int n,tot,sum[N<<5],ls[N<<5],rs[N<<5];
    LL ans,res1,res2;
    
    int update(int l,int r,int pos){
        int now=++tot; sum[now]=1; 
        if(l==r) return now; int mid=(l+r)>>1;
        if(pos<=mid) ls[now]=update(l,mid,pos);
        else rs[now]=update(mid+1,r,pos);
        sum[now]=sum[ls[now]]+sum[rs[now]];
        return now;
    }
    
    int merge(int u,int v,int l,int r){
        if(!u || !v) return (u|v);
        if(l==r) {sum[++tot]=sum[u]+sum[v]; return tot;}
        int mid=(l+r)>>1;	
        res1+=(LL)sum[rs[u]]*sum[ls[v]],res2+=(LL)sum[ls[u]]*sum[rs[v]];
        ls[u]=merge(ls[u],ls[v],l,mid); rs[u]=merge(rs[u],rs[v],mid+1,r);
        sum[u]+=sum[v]; return u;
    }
    
    int DFS(){
        int now=rd(),tmp,LS,RS;
        if(now) return update(1,n,now);
        LS=DFS(); RS=DFS(); tmp=merge(LS,RS,1,n);
        ans+=min(res1,res2); res1=res2=0;
        return tmp;
    }
    
    int main(){
        n=rd(); DFS();
        printf("%lld",ans);
        return 0;	
    }
    
  • 相关阅读:
    Vue源码探究-数据绑定的实现
    vue 数组遍历方法forEach和map的原理解析和实际应用
    vue 微信内H5调起支付
    uni-app官方教程学习手记
    vue-cli3 搭建的前端项目基础模板
    vue.js响应式原理解析与实现
    vue-waterfall2 基于Vue.js 瀑布流组件
    解决lucene更新删除无效的问题
    spring项目启动报错
    js监听页面copy事件添加版权信息
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10350472.html
Copyright © 2020-2023  润新知