zoukankan      html  css  js  c++  java
  • [BZOJ3289]Mato的文件管理

    题目大意

    给你(n)个数,(m)个询问

    每次询问一段区间([l,r]),可以进行交换相邻两个元素的操作,使这段区间从小到大排序的最小操作次数

    (n,mleq 50000),元素值在(1000000)内,没有重复元素

    解题思路

    这题第一感觉,好像和逆序对有关?

    那么给出性质:

    使区间[l,r]按题意方式从小到大排序的最小操作次数等价于区间[l,r]的逆序对总数

    这是一个很强的结论了

    尝试给出证明:

    首先证明操作次数的下限是逆序对个数

    很显然,每次操作(交换相邻两数)能且至多消除一个逆序对

    因此下限就是逆序对个数

    然后我们证明每次操作都可以消除一个逆序对

    同样很显然,假设不存在可以消除的逆序对,这意味着这个序列是有序的!

    同时,如果序列不是有序的,那么必定存在一对相邻的逆序对可以消除

    于是我们(类似贪心的)取到了最优方案

    维护

    于是这题就变成求区间逆序对个数了

    那么考虑用莫队和权值树状数组求解

    所谓权值树状数组,就是维护对应权值出现次数
    第i位上的值代表i的出现次数
    那么k的前缀和的含义就是不大于k的数一共有几个
    

    莫队最核心的就是得到指针移动对答案的影响

    我们考虑在末尾增加一个元素的情况:

    那个元素贡献的逆序对个数就是前面比它大的元素个数

    看样子需要两个权值树状数组,一个维护前缀和,一个后缀和?

    其实不用,因为比A大的元素个数就是总数-不大于A的元素个数

    这个可以直接用权值树状数组维护前缀和

    复杂度分析,(Blo=sqrt{n})最优

    复杂度(O(nsqrt{n}logn))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    const int Base=230;
    int Blo[70000];
    
    int n,q;
    
    namespace tarr{
        int T[100000];
        void clear(){memset(T,0,sizeof(T));}
        inline int lowbit(int k){return k&-k;}
        void add(int K,int v){
            while (K<=n){
                T[K]+=v;
                K+=lowbit(K);
            }
        }
        int query(int K){
            int ret=0;
            while (K){
                ret+=T[K];
                K-=lowbit(K);
            }
            return ret;
        }
    }    
    
    struct query{
        int x,y;
        int id;
    }Q[100000];
    bool cmp_q(query X,query Y){return Blo[X.x]<Blo[Y.x]||(Blo[X.x]==Blo[Y.x]&&X.y<Y.y);}
    
    struct val{
        int V,id;
    }V[100000];
    bool cmp_v(val A,val B){return A.V<B.V;}
    
    int U[100000],valcnt;
    int L,R,val;
    int ans[100000];
    
    int main(){
        tarr::clear();
        for (int i=0;i<=50000/Base;i++)
            for (int j=1;j<=Base;j++)
                Blo[i*Base+j]=i;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&V[i].V),V[i].id=i;
        std::sort(V+1,V+n+1,cmp_v);
        for (int i=1;i<=n;i++){
            if (V[i].V!=V[i-1].V) valcnt++;
            U[V[i].id]=valcnt;
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++) 
            scanf("%d%d",&Q[i].x,&Q[i].y),Q[i].id=i;
        std::sort(Q+1,Q+q+1,cmp_q);
        L=R=1;tarr::add(U[1],1);
        for (int i=1;i<=q;i++){
            while (R<Q[i].y){
                R++;
                val+=R-L-tarr::query(U[R]-1);
                tarr::add(U[R],1);
            }
            while (L>Q[i].x){
                L--;
                val+=tarr::query(U[L]-1);
                tarr::add(U[L],1);
            }
            while (R>Q[i].y){
                val-=R-L-tarr::query(U[R]-1);
                tarr::add(U[R],-1);
                R--;
            }
            while (L<Q[i].x){
                val-=tarr::query(U[L]-1);
                tarr::add(U[L],-1);
                L++;
            }
            ans[Q[i].id]=val;
        }
        for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    搭建一个redis高可用系统
    从“如何设计用户超过1亿的应用”说起----数据库调优实战
    单表60亿记录等大数据场景的MySQL优化和运维之道 | 高可用架构
    信息安全系统和安全体系
    敏捷开发系列之旅 第五站(不一样的RUP统一软件开发过程)
    微服务理论与实践(三)-微服务架构的基本能力和优缺点
    学习“CC攻击”
    查看IIS错误日志
    ISNULL函数
    IE6/7下Select控件Display属性无效解决办法
  • 原文地址:https://www.cnblogs.com/ytxytx/p/9820960.html
Copyright © 2011-2022 走看看