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\n",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;
}

 

posted @ 2018-07-26 22:37  符拉迪沃斯托克  阅读(191)  评论(0编辑  收藏  举报
Live2D