删除好像挺麻烦的。。那就考虑倒一下,也就是倒序加值。
考虑一个值加入进来,对答案的影响就是,它左边的比它大的个数和它右边比它小的个数加和。
先只考虑一半。只考虑右边比它小的数的个数。那么假设当前加入的为一个三元组
(t,pos,x)
,表示时间,位置和值。那么就是求满足
(tt<t,ppos>pos,xx<x)
的三元组
(tt,ppos,xx)
的个数。(因为把删除操作反过来进行了所以就是
tt<t
)。
那么三维偏序就可以考虑用
CDQ
分治。
当然这只完成了一半啦,剩下的一半其实也相同。
我偷了点懒。。想只写一遍
CDQ
。另外一半操作的时候,把位置和值都颠倒了一下。也就是原本应该插入的是
15342
,变成了
42315
。那么相当于每次也是求右边的比它小的个数啦。
对应到代码中:第一次操作是
for(int i=1;i<=n;i++) if(!flag[i]) Q[++tot]=Query(0,Pos[i],i,0);
for(int i=m;i;i--) {
Q[++tot]=Query(1,Pos[b[i]],b[i],m-i+1);
Q[++tot]=Query(0,Pos[b[i]],b[i],m-i+1);
}
后面一遍操作写成:
for(int i=1;i<=n;i++) if(!flag[i]) Q[++tot]=Query(0,n-Pos[i]+1,n-i+1,0);
for(int i=m;i;i--) {
Q[++tot]=Query(1,n-Pos[b[i]]+1,n-b[i]+1,m-i+1);
Q[++tot]=Query(0,n-Pos[b[i]]+1,n-b[i]+1,m-i+1);
}
Warning!
相同的位置应先查询再修改。
要开
longlong
.
Don′tForget
要求出删完的序列中逆序对的个数!
【代码】
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 100005
#define M 200005
using namespace std;
typedef long long ll;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,tot;
int a[N],b[N],Pos[N];
ll szsz[N],ans[N],PreAns;
bool flag[N];
class Query{
public:
int type,pos,x,id;
Query(){}
Query(int tt,int pp,int xx,int ii){
type=tt,pos=pp,x=xx,id=ii;
}
}Q[M],tmp[M];
bool operator <(Query a,Query b){
return a.pos>b.pos||(a.pos==b.pos&&a.type>b.type);
}
int lowbit(int x){return x&-x;}
void Sum_Up(int x,int y){
for(int i=x;i<=n;i+=lowbit(i)) szsz[i]+=y;
}
ll query(int x){
ll rtn=0;
for(int i=x;i;i-=lowbit(i)) rtn+=szsz[i];
return rtn;
}
void Clear(int x){
for(int i=x;i<=n&&szsz[i];i+=lowbit(i)) szsz[i]=0;
}
void Input_Init()
{
n=read();m=read();
for(int i=1;i<=n;i++) Pos[a[i]=read()]=i;
for(int i=1;i<=m;i++) flag[b[i]=read()]=1;
for(int i=1;i<=n;i++) if(!flag[i]) Q[++tot]=Query(0,Pos[i],i,0);
for(int i=m;i;i--) {
Q[++tot]=Query(1,Pos[b[i]],b[i],m-i+1);
Q[++tot]=Query(0,Pos[b[i]],b[i],m-i+1);
}
}
int st[N],top;
void Get_PreAns()
{
for(int i=1;i<=n;i++) if(!flag[a[i]]) st[++top]=a[i];
for(int i=1;i<=top;i++)
{
PreAns+=i-1-query(st[i]);
Sum_Up(st[i],1);
}
for(int i=1;i<=top;i++) Clear(st[i]);
}
bool Judge(Query a,Query b){
return a.pos<b.pos||(a.pos==b.pos&&a.type>b.type);
}
void CDQ(int L,int R)
{
if(L==R) return;
int mid=L+R>>1;CDQ(L,mid);CDQ(mid+1,R);
int p=L,q=mid+1,o=0;
while(p<=mid&&q<=R) {
if(Q[p]<Q[q]) {
if(!Q[p].type) Sum_Up(Q[p].x,1);
tmp[o++]=Q[p++];
}
else {
if(Q[q].type) ans[Q[q].id]+=query(Q[q].x);
tmp[o++]=Q[q++];
}
}
while(p<=mid) tmp[o++]=Q[p++];
while(q<=R) {
if(Q[q].type) ans[Q[q].id]+=query(Q[q].x);
tmp[o++]=Q[q++];
}
for(int i=0;i<o;i++) {
Q[i+L]=tmp[i];
Clear(tmp[i].x);
}
}
void Re_Make()
{
tot=0;
for(int i=1;i<=n;i++) if(!flag[i]) Q[++tot]=Query(0,n-Pos[i]+1,n-i+1,0);
for(int i=m;i;i--) {
Q[++tot]=Query(1,n-Pos[b[i]]+1,n-b[i]+1,m-i+1);
Q[++tot]=Query(0,n-Pos[b[i]]+1,n-b[i]+1,m-i+1);
}
}
void Solve()
{
CDQ(1,tot);
Re_Make();CDQ(1,tot);ans[0]=PreAns;
for(int i=1;i<=m;i++) ans[i]=ans[i-1]+ans[i];
for(int i=m;i;i--) printf("%lld\n",ans[i]);
}
int main()
{
Input_Init();
Get_PreAns();
Solve();
return 0;
}