BZOJ 3295 动态逆序对

来源:互联网 发布:最大域名注册商 编辑:程序博客网 时间:2024/06/07 01:56

题意:给定一个包含1~n的序列(不含重复数),求删除一个数前的逆序对数

思路:我看我的代码,这用的应该是树状数组套线段树,原意是主席树,但是根本没有重用任何节点。

            树状数组用于区间查询,线段树用于维护这些数。

#include<stdio.h>#include<string.h>#define LL long longconst int maxn = 1e5+10;const int maxe = 9e6;int root[maxn],a[maxn],Rank[maxn];int ls[maxe],rs[maxe],sz[maxe];int Q1[1000],Q2[1000],q1,q2;int n,tot,m,t;int lowbit(int x){return -x&x;}void ins(int &x,int l,int r,int key,int v){    if(!x) {x=++tot;}    sz[x]+=v;    if(l==r) return;    int m = (l+r)/2;    if(key<=m) ins(ls[x],l,m,key,v);    else ins(rs[x],m+1,r,key,v);}void my_ins(int pos,int x,int v){    for(int i=pos;i<=n;i+=lowbit(i))        ins(root[i],1,n,x,v);}LL Qy(int l,int r,int k,bool big) //big标记查询的是比k大还是比k小{    LL res = 0;    if(l>=r) return 0;    int m = (l+r)/2;    if(m>=k) //左边    {        if(big){            for(int i=0;i<q1;i++) res -= sz[rs[Q1[i]]];            for(int i=0;i<q2;i++) res += sz[rs[Q2[i]]];        }        for(int i=0;i<q1;i++) Q1[i] = ls[Q1[i]];        for(int i=0;i<q2;i++) Q2[i] = ls[Q2[i]];        return res + Qy(l,m,k,big);    }    else //右边    {        if(!big){            for(int i=0;i<q1;i++) res -= sz[ls[Q1[i]]];            for(int i=0;i<q2;i++) res += sz[ls[Q2[i]]];        }        for(int i=0;i<q1;i++) Q1[i] = rs[Q1[i]];        for(int i=0;i<q2;i++) Q2[i] = rs[Q2[i]];        return res + Qy(m+1,r,k,big);    }    return res;}LL query(int l,int r,int k,bool big){    q1 = q2 = 0;    for(int i=l-1;i>0;i-=lowbit(i)) Q1[q1++]=root[i];    for(int i=r;i>0;i-=lowbit(i)) Q2[q2++]=root[i];    return Qy(1,n,k,big);}int main(){    scanf("%d%d",&n,&m);    LL ans = 0;    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        my_ins(i,a[i],1);        Rank[a[i]]=i;        ans += query(1,i,a[i],1);    }    printf("%lld\n",ans);    for(int i=1;i<m;i++)    {        scanf("%d",&t);        my_ins(Rank[t],t,-1);        ans -= query(1,Rank[t]-1,t,1);        ans -= query(Rank[t]+1,n,t,0);        printf("%lld\n",ans);    }    return 0;}


0 0