【题解】【uva11990】【bzoj3295】动态逆序对 ``Dynamic'' Inversion

来源:互联网 发布:夜神模拟器清理数据 编辑:程序博客网 时间:2024/06/05 00:33

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


题解:

首先我们可以想到这样的做法:先求出原有的逆序对的数量,然后每删除一个元素,计算删除掉的逆序对的数量。

方法是计算该元素前有多少个元素比它大,后面有多少个元素比它小即可。

但是如果暴力计算删除掉的逆序对的数量是O(n)的,也就是说整个程序的时间复杂度高达O(n*m),对于这样的数据范围显然无法承受。

这时我们发现计算删除掉的逆序对的过程是区间求值,因此我们可以使用树状数组实现(树状数组常数小)。为了维护元素的大小关系,普通的树状数组显然无法完成,这时候就可以使用树状数组套平衡树的方法来达到快速求区间元素大小关系的任务。

当然,本题中没有插入、修改操作,只有删除,因此不需要动态维护平衡的Treap,Splay等,构建一棵静态的BST即可,对于删除的点打上标记就能达到O(logn)求元素排名的效果。

也就是说,我们用树状数组套BST的方法解决了本题,时间复杂度为O(m*log(n)*log(n))。


注意:使用long long。(我卡了一个晚上)


代码:

#include <bits/stdc++.h>using namespace std;int n,m,pos[1000001],a[1000001];struct node{node *l,*r;int v;int deleted,cnt;}*null;struct BST{vector<int> list;node *root;void prepare(int x){list.push_back(x);}void build(){sort(list.begin(),list.end());build(root=new node,0,list.size()-1);list.clear();}void build(node *now,int l,int r){now->l=now->r=null;int m=(l+r)>>1;now->v=list[m];now->cnt=1;now->deleted=0;if(l!=r){if(l<=m-1)build(now->l=new node,l,m-1);build(now->r=new node,m+1,r);}now->cnt+=now->l->cnt+now->r->cnt;}long long smaller(node *now,int v){if(now==null)return 0;if(now->v<v){return now->l->cnt-now->deleted+now->r->deleted+1+smaller(now->r,v);}else{return smaller(now->l,v);}}long long bigger(node *now,int v){if(now==null)return 0;if(now->v>v){return now->r->cnt-now->deleted+now->l->deleted+1+bigger(now->l,v);}else{return bigger(now->r,v);}}void erase(node *now,int val){++now->deleted;if(now->v==val)return;if(now->v>val)erase(now->l,val);elseerase(now->r,val);}void clear(node *now){if(now==null || now==NULL)return;clear(now->l);clear(now->r);delete now;}void debug(node *now){if(now->l!=null)debug(now->l);printf("%d ",now->v);if(now->r!=null)debug(now->r);}};struct Fenwick{BST c[200001];int lowbit(int _x){return _x&-_x;}void add(int ind,int num){while(ind<=n){c[ind].prepare(num);ind+=lowbit(ind);}}void del(int ind,int num){while(ind<=n){c[ind].erase(c[ind].root,num);ind+=lowbit(ind);}}void build(){for(int i=1;i<=n;++i)c[i].build();}long long querybig(int index,int v){long long sum=0;while(index>0){sum+=c[index].bigger(c[index].root,v);index-=lowbit(index);}return sum;}long long querysmall(int index,int v){long long sum=0,id=index;index=n;while(index>0){sum+=c[index].smaller(c[index].root,v);index-=lowbit(index);}index=id;while(index>0){sum-=c[index].smaller(c[index].root,v);index-=lowbit(index);}return sum;}long long query(int index,int v){return querybig(index,v)+querysmall(index,v);}}tree;int main(){null=new node;null->cnt=null->deleted=0;while(~scanf("%d%d",&n,&m)){for(int i=1;i<=n;++i)tree.c[i].clear(tree.c[i].root);for(int i=1;i<=n;++i){scanf("%d",a+i);pos[a[i]]=i;tree.add(i,a[i]);}tree.build();long long cnt=0;for(int i=1;i<=n;++i)cnt+=tree.query(i,a[i]);cnt/=2;for(int i=1;i<=m;++i) {printf("%lld\n",cnt);int x,id;scanf("%d",&x);id=pos[x];cnt-=tree.query(id,a[id]);tree.del(id,a[id]);}}}


原创粉丝点击