BZOJ 3295 [Cqoi2011]动态逆序对

来源:互联网 发布:pm2.5数据接口 编辑:程序博客网 时间:2024/06/05 03:55

首先预处理,对于一个输入的数列求逆序对个数利用树状数组nlogn即可解决。

然后考虑删点的问题。每次删点需要在总ans中删去此节点前比此数大的数的个数和之后此数小的个数。

对于当前的节点,如果需要定点查询一段区间中比一定值c大或小的点的个数,只需要在线段树(或平衡树)上操作即可。而对于这道题,需要讨论每个点,即每个点均需建立一棵线段树。每次查询之后需要在每棵线段树上进行修改操作,单次复杂度logn,每棵则为nlogn,m次则为O(mnlogn),很明显时间无法接受,空间也无法接受,于是可以用树状数组优化。

从另一个方面考虑:如果不考虑查询的是一个区间(即不具有最大或最小值的限定)树状数组通过lowbit记录一条删除的路径,路径上每个点-1,下次查询时沿路径累加即可修正ans;而如果有最大最小值的范围限定,则需要利用线段树(或平衡树)查询。每个节点均需要一棵树支持区间查询,由此进行树套树。


树状数组套主席树

Time:4100 ms

Memory:115672 kb

#include<iostream>#include<cstdlib>#include<cstdio>#include<algorithm>#include<cstring>  using namespace std;  const int maxn=160005;  struct tree{    int lson,rson,val;}t[maxn*60];  int n,m,cnt;long long ans;int f[maxn];int c[maxn];int s[maxn];  void build_init(int &ro,int l,int r){    ro=++cnt;    if(l==r)return;    int mid=l+r>>1;    build_init(t[ro].lson,l,mid);    build_init(t[ro].rson,mid+1,r);}void build_seg(int &ro,int pos,int val,int l,int r){    if(!ro)ro=++cnt;    t[ro].val+=val;    if(l==r)return;    int mid=l+r>>1;    if(pos<=mid)build_seg(t[ro].lson,pos,val,l,mid);    else build_seg(t[ro].rson,pos,val,mid+1,r);}int query_seg(int ro,int maxi,int l,int r){    if(r==maxi)return t[ro].val;    int mid=l+r>>1;    if(mid>=maxi)return query_seg(t[ro].lson,maxi,l,mid);    return query_seg(t[ro].rson,maxi,mid+1,r)+t[t[ro].lson].val;}void update_tree(int x,int pos,int val){    int tmp;    for(int i=x;i<=n;i+=i&-x)        build_seg(c[i],pos,val,1,n);}long long query_tree(int x,int maxi){    long long res=0;    for(int i=x;i;i-=i&-i)        res+=query_seg(c[i],maxi,1,n);    return res;}void update(int x){    for(int i=x;i<=n;i+=i&-i)s[i]++;}int query(int x){    int res=0;    for(int i=x;i;i-=i&-i)res+=s[i];    return res;}long long getans(int pos,int a){    return query_tree(pos,n)-query_tree(pos,a)+query_tree(n,a)-query_tree(pos,a);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        int a;        scanf("%d",&a);        f[a]=i;        update_tree(i,a,1);        update(a);        ans+=query(n)-query(a);    }         for(int i=1;i<=m;i++)    {        printf("%lld\n",ans);        int a;        scanf("%d",&a);        update_tree(f[a],a,-1);        ans-=getans(f[a],a);    }} 

树状数组套treap

Time:10376 ms

Memory:38152 kb

注意可以建立一个空节点null,将NULL替换成null避免因为访问空指针而RE。

#include<iostream>#include<cstdlib>#include<cstdio>#include<algorithm>#include<cstring>  using namespace std;  const int maxn=160005; struct node{    int rank,val,size;    node *son[2];         bool cmp(int val_)    {        return val<val_;    }     }Tnull,*null=&Tnull;  int n,m,cnt;long long ans;int f[maxn];node* c[maxn];int s[maxn];  node* newnode(node *&o,int val_){    o=new node;    o->son[0]=o->son[1]=null;    o->rank=rand();    o->val=val_;    o->size=1;}void maintain(node *o){    o->size=1;    if(o->son[0]!=null)o->size+=o->son[0]->size;    if(o->son[1]!=null)o->size+=o->son[1]->size;}void rotate(node *&o,bool d){    node *p=o->son[d];o->son[d]=p->son[d^1];p->son[d^1]=o;    maintain(o);maintain(p);o=p;}void insert(node *&o,int val){    if(o==null)o=newnode(o,val);    else    {        bool d=o->cmp(val);        insert(o->son[d],val);        if(o->son[d]->rank > o->rank)            rotate(o,d);    }    maintain(o);}void del(node *&o,int val){    if(o->val==val)    {        node *p=o;        if(o->son[0]!=null&&o->son[1]!=null)        {            bool d=o->son[0]->rank < o->son[1]->rank;            rotate(o,d);            del(o->son[d^1],val);        }        else        {            if(o->son[0]!=null)o=o->son[0];            else o=o->son[1];            delete p;        }    }    else {        bool d=o->cmp(val);        del(o->son[d],val);        }    if(o!=null)maintain(o);} int count(node *o,int maxi){    if(o==null)return 0;    if(maxi>o->val)return o->son[0]->size+1+count(o->son[1],maxi);    return count(o->son[0],maxi)+(maxi==o->val);}void update_tree(int x,int pos){    for(int i=x;i<=n;i+=i&-i)    {        if(!c[i])newnode(c[i],pos);        else insert(c[i],pos);    }}void delete_tree(int x,int pos){    for(int i=x;i<=n;i+=i&-i)        del(c[i],pos);}long long query_tree(int x,int maxi){    long long res=0;    for(int i=x;i;i-=i&-i)        res+=count(c[i],maxi);    return res;}void update(int x){    for(int i=x;i<=n;i+=i&-i)s[i]++;}int query(int x){    int res=0;    for(int i=x;i;i-=i&-i)res+=s[i];    return res;}long long getans(int pos,int a){    return query_tree(pos,n)-query_tree(pos,a)+query_tree(n,a)-query_tree(pos,a);}int main(){    srand(20170901);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        int a;        scanf("%d",&a);        f[a]=i;        update_tree(i,a);        update(a);        ans+=query(n)-query(a);    }    for(int i=1;i<=m;i++)    {        printf("%lld\n",ans);        int a;        scanf("%d",&a);        delete_tree(f[a],a);        ans-=getans(f[a],a);    }} 


原创粉丝点击