• cf1268C——线段树,逆序对


    /*
    结果肯定和 逆序对数量有关,假设当前求第k个答案:
        如果1-k元素连续,则只要求出1-k的逆序对个数即可
        如果不连续,那么先把这k个元素移动到一起,然后再求逆序对
            移动的策略是二分找中间位置p,p左边的元素数量=p右边的元素数量 
    
    所以用线段树去维护当前已经存在的点位置
        每次求答案:二分找位置p,求最小移动代价,求逆序对 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 200005
    
    int n;
    struct Node{
        int pos,v;
    }p[N];
    int cmp(Node &a, Node & b){return a.v<b.v;}
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll sum1[N<<2],sum2[N<<2];
    void update(int pos,int l,int r,int rt){
        if(l==r){sum1[rt]=1;sum2[rt]=l;return;}
        int m=l+r>>1;
        if(pos<=m)update(pos,lson);
        else update(pos,rson);
        sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
        sum2[rt]=sum2[rt<<1]+sum2[rt<<1|1];
    }
    ll query1(int L,int R,int l,int r,int rt){
        if(L>R)return 0;
        if(L<=l && R>=r)return sum1[rt];
        int m=l+r>>1;
        ll res=0;
        if(L<=m)res+=query1(L,R,lson);
        if(R>m)res+=query1(L,R,rson);
        return res;
    }
    ll query2(int L,int R,int l,int r,int rt){
        if(L>R)return 0;
        if(L<=l && R>=r)return sum2[rt];
        int m=l+r>>1;
        ll res=0;
        if(L<=m)res+=query2(L,R,lson);
        if(R>m)res+=query2(L,R,rson);
        return res;
    }
    int query(int k,int l,int r,int rt){
        if(l==r)return l;
        int m=l+r>>1;
        if(k<=sum1[rt<<1])return query(k,lson);
        else return query(k-sum1[rt<<1],rson);
    }
    
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%d",&p[i].v),p[i].pos=i;
        sort(p+1,p+1+n,cmp);
        
        ll rev=0; 
        for(int i=1;i<=n;i++){
            update(p[i].pos,1,n,1);
            
            //二分找到第一个中点 
            int ans=query(i/2+i%2,1,n,1); 
            
            ll Sum1=query2(1,ans-1,1,n,1);//ans前面的和 
            ll Sum2=query2(ans+1,n,1,n,1);//ans后面的和 
            ll cnt1=query1(1,ans-1,1,n,1);//ans前面个数 
            ll cnt2=query1(ans+1,n,1,n,1);//ans后面个数 
            
            ll cost=(Sum2-ans*cnt2)+(ans*cnt1-Sum1);
            if (cnt2)cost-=cnt2*(cnt2+1)/2;
            if (cnt1)cost-=(cnt1+1)*cnt1/2;
             
            rev+=query1(p[i].pos+1,n,1,n,1);
            cout<<cost+rev<<" ";
        }
        puts("");
    } 
  • 相关阅读:
    使用 Cheat Engine 修改 Kingdom Rush 中的金钱、生命、星
    rxjava回调地狱kotlin协程来帮忙
    vue2.0 双向绑定原理分析及简单实现
    取消数字输入框后小箭头
    flink 水位、窗口、乱序、延迟与侧输出流
    世界公认7大管理法则[转]
    一个数组中有两种数出现了奇数次,其他数都出现了偶数次,寻找这两个数
    插入排序
    prometheus+grafana+alertmanager监控系统搭建 若
    关于 Excel 导出时候不能创建 object 修改办法
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12132787.html
Copyright © 2020-2023  润新知