zoukankan      html  css  js  c++  java
  • 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("");
    } 
  • 相关阅读:
    Flash 全局安全性设置面板
    响应式布局的一个例子mark
    移动平台WEB前端开发技巧汇总
    自定义事件机制——观察者模式
    学习之响应式Web设计:Media Queries和Viewports
    常用栅格布局方案
    观察者模式的一个例子
    二进制文件转换为文本工具
    C#面向对象名词比较(二)
    MSN消息提示类
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12132787.html
Copyright © 2011-2022 走看看