bzoj3295 动态逆序对

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

思路:如果倒着看的话,就变成了插入操作,第一个删除的数使最后一个插入的数,我们用<x,y,t>来表示每个插入操作,x表示插入位置,y表示插入的数,t表示插入的时间,对时间进行二分操作,每次保证左边区间的时间都小于右边区间的时间,并且每个区间的x都是递增的

_left[i]表示第i次操作后,和左边的数新构成的逆序对的对数

_right[i]表示第i次操作后,和右边的数新构成的逆序对的对数

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f

const int maxn=1e5+50;
struct Node{
    int x,y,t;
}q[maxn],q1[maxn],q2[maxn];
struct BIT{
    int n,b[maxn];
    void init(int _n){
        n=_n;
        mm(b,0);
    }
    void add(int i,int val){
        for(;i<=n;i+=i&(-i))
            b[i]+=val;
    }
    int sum(int i){
        int ret=0;
        for(;i>0;i-=i&(-i))
            ret+=b[i];
        return ret;
    }
}bit;
int pos[maxn];
LL ans[maxn];
int _left[maxn],_right[maxn];
int n,m;
void cdq(int L,int R){
    if(L>=R) return;
    int sz1=0,sz2=0;
    int mid=(L+R)>>1;
    for(int i=L;i<=R;i++){
        if(q[i].t<=mid) q1[sz1++]=q[i];
        else q2[sz2++]=q[i];
    }
    int j=0;
    for(int i=0;i<sz2;i++){
        for(;j<sz1&&q1[j].x<q2[i].x;j++)
            bit.add(q1[j].y,1);
        _left[q2[i].t]+=bit.sum(n)-bit.sum(q2[i].y);
    }
    for(int i=0;i<j;i++)
        bit.add(q1[i].y,-1);

    j=sz1-1;
    for(int i=sz2-1;i>=0;i--){
        for(;j>=0&&q1[j].x>q2[i].x;j--)
            bit.add(q1[j].y,1);
        _right[q2[i].t]+=bit.sum(q2[i].y-1);
    }
    for(int i=sz1-1;i>j;i--)
        bit.add(q1[i].y,-1);
    memcpy(q+L,q1,sz1*sizeof(Node));
    memcpy(q+L+sz1,q2,sz2*sizeof(Node));
    cdq(L,mid);
    cdq(mid+1,R);
}
int main(){

//    freopen("D:\\input.txt","r",stdin);
//    freopen("D:\\output.txt","w",stdout);
    int x;
    while(~scanf("%d%d",&n,&m)){
        bit.init(n);
        for(int i=1;i<=n;i++){
            scanf("%d",&q[i].y);
            q[i].x=i;q[i].t=0;
            pos[q[i].y]=i;
            ans[i]=_left[i]=_right[i]=0;
        }
        int tim=n;
        for(int i=1;i<=m;i++){
            scanf("%d",&x);
            q[pos[x]].t=tim--;
        }
        for(int i=1;i<=n;i++)
            if(q[i].t==0)
                q[i].t=tim--;
//        PP;
//        for(int i=1;i<=n;i++)
//            printf("%d %d %d\n",q[i].x,q[i].y,q[i].t);
        cdq(1,n);
        ans[0]=_left[0]=_right[0]=0;
        for(int i=1;i<=n;i++)
            ans[i]=ans[i-1]+_left[i]+_right[i];
        for(int i=n;i>n-m;i--)
            printf("%lld\n",ans[i]);
//        PP;
//        for(int i=1;i<=n;i++)
//            printf("%d  %d  %d\n",i,_left[i],_right[i]);
//        for(int i=1;i<=n;i++)
//            printf("%d ",bit.b[i]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值