zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    如何将网格式报表打印成其它样式
    拥有与实力不相称的脾气是种灾难——北漂18年(23)
    8.8.1 Optimizing Queries with EXPLAIN
    mysql 没有rowid 怎么实现根据rowid回表呢?
    secondary index
    8.5.5 Bulk Data Loading for InnoDB Tables 批量数据加载
    mysql 中key 指的是索引
    8.5.4 Optimizing InnoDB Redo Logging 优化InnoDB Redo 日志
    8.5.3 Optimizing InnoDB Read-Only Transactions 优化InnoDB 只读事务
    8.5.1 Optimizing Storage Layout for InnoDB Tables InnoDB表的存储布局优化
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9374900.html
Copyright © 2011-2022 走看看