• BZOJ3295: [Cqoi2011]动态逆序对


    BZOJ3295: [Cqoi2011]动态逆序对

    Description

    对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。
    给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数

    Input

    输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
    以下n行每行包含一个1到n之间的正整数,即初始排列。
    以下m行每行一个正整数,依次为每次删除的元素。
    N<=100000 M<=50000

    Output

    输出包含m行,依次为删除每个元素之前,逆序对的个数。

    Sample Input

    5 4
    1
    5
    3
    4
    2
    5
    1
    4
    2

    Sample Output

    5
    2
    2
    1
    样例解释
    (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
    题解Here!

    据说正解是cdq分治?本蒟蒻并不会。。。

    于是想起了这题:P1774 最接近神的人_NOI导刊2010提高(02)

    那题是静态的逆序对,而这题要支持删除操作。

    静态逆序对用了什么?树状数组!

    树状数组维护什么?前缀和!

    动态前缀和怎么维护?主席树!

    于是一个树状数组套主席树就这么被YY构造出来了。。。

    删除第一个前的逆序对自然能求出来.

    此时我们考虑删除第一个元素,减少的逆序对个数就是在它前面的比他大的和在它后面比它小的,于是我们开两个数组来存:

    sum_one[i] 表示的就是在i前面而且大于i位置上的元素的元素的个数。

    sum_two[i] 表示的就是在i后面而且小于i位置上的元素的元素的个数。

    sum_one[i] 就可以在读入的时候直接处理一下。

    sum_two[i] 可以反向添加然后处理出来。

    但是又有一个问题了,我已经删了的还是被计算在内了,怎么办?

    我减去它与已经删了的构成的逆序对的个数不就好了吗?

    于是问题变成了:

    每一次在已经删除的元素里面找 [l,r] 里面小于某个数的元素的个数。

    这个问题显然丢给主席树。

    注:记得开大空间!我就是数组开小了然后 MLE* 2 。。。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define MAXN 100010
    using namespace std;
    int n,m;
    long long ans=0;
    int val[MAXN],pos[MAXN],sum_one[MAXN],sum_two[MAXN];
    inline int read(){
        int date=0,w=1;char c=0,last=0;
        while(c<'0'||c>'9'){last=c;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        if(last=='-')w=-1;
        return date*w;
    }
    namespace CT{
        int size=1,s1,s2,root[MAXN],lrt[MAXN/1000+10],rrt[MAXN/1000+10];
        struct Charman_Tree{
            int l,r,sum;
        }a[MAXN*100];
        void insert(int k,int l,int r,int &rt){
            a[size]=a[rt];rt=size++;
            a[rt].sum++;
            if(l==r)return;
            int mid=l+r>>1;
            if(k<=mid)insert(k,l,mid,a[rt].l);
            else insert(k,mid+1,r,a[rt].r);
        }
        int query_front(int l,int r,int k){
            if(l==r)return 0;
            int mid=l+r>>1,t=0;
            for(int i=1;i<=s1;i++)t-=a[a[lrt[i]].r].sum;
            for(int i=1;i<=s2;i++)t+=a[a[rrt[i]].r].sum;
            if(k<=mid){
                for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].l;
                for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].l;
                return t+query_front(l,mid,k);
            }
            else{
                for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].r;
                for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].r;
                return query_front(mid+1,r,k);
            }
        }
        int query_next(int l,int r,int k){
            if(l==r)return 0;
            int mid=l+r>>1,t=0;
            for(int i=1;i<=s1;i++)t-=a[a[lrt[i]].l].sum;
            for(int i=1;i<=s2;i++)t+=a[a[rrt[i]].l].sum;
            if(k>mid){
                for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].r;
                for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].r;
                return t+query_next(mid+1,r,k);
            }
            else{
                for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].l;
                for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].l;
                return query_next(l,mid,k);
            }
        }
        inline int lowbit(int x){return x&(-x);}
        inline void update(int x,int v){
            for(int i=x;i<=n;i+=lowbit(i))insert(v,1,n,root[i]);
        }
        inline int get_answer(int l,int r,int k){
            int s=0;
            s1=s2=0;
            for(int i=0;i;i-=lowbit(i))lrt[++s1]=root[i];
            for(int i=l;i;i-=lowbit(i))rrt[++s2]=root[i];
            s+=query_front(1,n,k);
            s1=s2=0;
            for(int i=r-1;i;i-=lowbit(i))lrt[++s1]=root[i];
            for(int i=n;i;i-=lowbit(i))rrt[++s2]=root[i];
            s+=query_next(1,n,k);
            return s;
        }
    }
    namespace BIT{
        int tree[MAXN];
        inline void init(){memset(tree,0,sizeof(tree));}
        inline int lowbit(int x){return x&(-x);}
        inline void update(int x,int v){for(;x<=n;x+=lowbit(x))tree[x]+=v;}
        inline int sum(int x){int s=0;for(;x;x-=lowbit(x))s+=tree[x];return s;}
    }
    void work(){
        int x,id;
        while(m--){
            printf("%lld
    ",ans);
            x=read();x=pos[x];
            ans-=(sum_one[x]+sum_two[x]-CT::get_answer(x-1,x+1,val[x]));
            CT::update(x,val[x]);
        }
    }
    void init(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            val[i]=read();
            pos[val[i]]=i;
            sum_one[i]=BIT::sum(n)-BIT::sum(val[i]);
            ans+=(long long)sum_one[i];
            BIT::update(val[i],1);
        }
        BIT::init();
        for(int i=n;i>=1;i--){
            sum_two[i]=BIT::sum(val[i]-1);
            BIT::update(val[i],1);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    wamp的安装
    原型模式(clone模式)
    观察者模式observer(用于不同类的中 板块的显示或其它操作)
    数据对象映射模式(通过工厂模式和注册树模式)v2
    数据对象映射模式(及对象的相关属性和数据库表中的字段一一对应)
    策略模式根据不同的性别给出不同的推荐
    适配器模式(数据库方面)支持不同的数据库连接
    php的三种设计模式
    UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only解决办法
    SQL语句如何在同一个表内复制一条记录
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9374900.html
Copyright © 2020-2023  润新知