首先预处理,对于一个输入的数列求逆序对个数利用树状数组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);
}
}