题意:给出一个数列,依次删除其中m个,求每一个数字删去后,剩余数列有多少个逆序对
分析:
很直观很暴力的想法,树套树:外层线段树,内层平衡树。
在线段树每个节点建一颗平衡树,平衡树中有这个范围内存在(未被删去)的数。
为节约时间,从后往前做加入操作(离线)。
每次删除(查询)ai,在已有的ans上,加入在1—i-1内找比ai大的数,以及i+1—n内找比ai小的数的总数
注意:
这是暴力数据结构的方法,时间为O(nlog²n)。常数也相当大,估计得卡一会儿。。
平衡树建议使用treap,splay常数过大
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define SF scanf
#define PF printf
#define INF 0x7FFFFFFF
#define MAXN 100010
#define LUCKY_NUM 20020214
using namespace std;
int summ,summ1;
int tot=1,a[MAXN],b[MAXN],se[MAXN],vis[MAXN];
struct node{
node *ch[2];
int r,v,num,num1;
node (int v):v(v) {
num=1;
num1=1;
ch[0]=ch[1]=NULL;
r=rand();
}
bool operator < (const node &rhs) const{
return r<rhs.r;
}
int cmp (int x) const{
if(x==v) return -1;
return x < v ? 0 : 1;
}
};
node * Root[MAXN*4];
int maxi,mini;
void rotate(node * &o,int d){
node *k=o->ch[!d];
o->ch[!d]=k->ch[d];
k->ch[d]=o;
o=k;
node * o1=o->ch[d];
o1->num1=o1->num;
if(o1->ch[0]!=NULL)
o1->num1+=o1->ch[0]->num1;
if(o1->ch[1]!=NULL)
o1->num1+=o1->ch[1]->num1;
o->ch[d]=o1;
o->num1=o->num;
if(o->ch[0]!=NULL)
o->num1+=o->ch[0]->num1;
if(o->ch[1]!=NULL)
o->num1+=o->ch[1]->num1;
}
int find(node * o, int x){
while(o != NULL)
{
int d = o->cmp(x);
if(d == -1) return 1;
else o = o->ch[d];
}
return 0;
}
void insert(node * &o,int x){
if(o==NULL)
o=new node(x);
else{
int d=o->cmp(x);
if(d==-1){
o->num++;
o->num1++;
return ;
}
o->num1++;
insert(o->ch[d],x);
if(o->ch[d]->r > o->r)
rotate(o,!d);
}
}
void dele(node * &o,int x){
if(o==NULL) return ;
if(o->v==x){
if(o->num>=2){
o->num1--;
o->num--;
return ;
}
if(o->ch[0]==NULL||o->ch[1]==NULL){
if(o->ch[0]==NULL)
o=o->ch[1];
else
o=o->ch[0];
}
else if(o->ch[0]->r < o->ch[1]->r){
rotate(o,1);
dele(o,x);
}
else{
rotate(o,0);
dele(o,x);
}
}
else if(x> o->v){
o->num1--;
dele(o->ch[1],x);
}
else{
o->num1--;
dele(o->ch[0],x);
}
}
int ask3(node * o,int x){
if(o==NULL)
return 0;
int d=o->cmp(x);
if(d==-1){
if(o->ch[0]==NULL)
return 1;
return o->ch[0]->num1 + 1;
}
if(d==0)
return ask3(o->ch[d],x);
else{
if(o->ch[0]==NULL)
return o->num+ask3(o->ch[d],x);
return o->ch[!d]->num1 + o->num + ask3(o->ch[d],x);
}
}
struct Tree{
int pl,pr,id,l,r;
}t[MAXN*4];
void build(int id,int l,int r){
t[id].l=l;
t[id].r=r;
if(l==r)
return ;
int mid=(l+r)/2;
tot++;
t[id].pl=tot;
build(tot,l,mid);
tot++;
t[id].pr=tot;
build(tot,mid+1,r);
}
void intree(int id,int x){
int y=se[x];
int mid=(t[id].l+t[id].r)/2;
insert(Root[id],x);
if(t[id].l==t[id].r)
return ;
if(mid>=se[x])
intree(t[id].pl,x);
else
intree(t[id].pr,x);
}
long long nx(int id,int x){
int y=se[x];
long long res=0;
if(t[id].r<y){
if(Root[id]==NULL)
res=0;
else
res=Root[id]->num1-ask3(Root[id],x);
return res;
}
else if(t[id].l>y){
res=ask3(Root[id],x);
return res;
}
if(t[id].pl!=0)
res+=nx(t[id].pl,x);
if(t[id].pr!=0)
res+=nx(t[id].pr,x);
return res;
}
int n,m;
long long ans,ans1[MAXN];
int main(){
//freopen("inverse.in","r",stdin);
//freopen("inverse.out","w",stdout);
SF("%d%d",&n,&m);
for(int i=1;i<=n;i++){
SF("%d",&a[i]);
se[a[i]]=i;
}
for(int i=1;i<=m;i++){
SF("%d",&b[i]);
vis[b[i]]=1;
}
build(1,1,n);
for(int i=1;i<=n;i++){
if(vis[a[i]]==0){
intree(1,a[i]);
ans+=nx(1,a[i]);
}
}
for(int i=m;i>=1;i--){
intree(1,b[i]);
ans+=nx(1,b[i]);
ans1[i]=ans;
}
for(int i=1;i<=m;i++)
PF("%lld\n",ans1[i]);
}