思路很容易想,麻烦的就是要实现一下动态开点线段树的修改操作,由于传统的主席树是依赖于前一个版本,所以如果想修改的话时间复杂度肯定会爆炸,于是我们想到了树状数组这个东西,把我们要修改的,线段树的个数降低到了log级别,而每次修改也是log,所以时间复杂度上是过的去的,怕卡常的话可以加个快读快写,然后注意开一下Long long。
所谓树状数组套线段树,就是把朴素版的树状数组里的一个个元素换成一颗颗独立的线段树,大体的操作没有变,就是在修改值的时候用到了动态开点线段树的修改。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define int long long
using namespace std;
const int N=1e5+10;
int n,idx,q;
int root[N*16*6];
struct xdss
{
int lson,rson,cnt;
}xds[N*16*6];
void motify(int &rt,int l,int r,int pos,int val)
{
if(!rt) rt=++idx;
xds[rt].cnt+=val;
if(l==r) return;
int mid=l+r>>1;
if(pos<=mid) motify(xds[rt].lson,l,mid,pos,val);
else motify(xds[rt].rson,mid+1,r,pos,val);
}
int query(int rt,int l,int r,int ll,int rr)
{
if(rt==0) return 0;
if(ll<=l&&r<=rr) return xds[rt].cnt;
int mid=l+r>>1;
int res=0;
if(ll<=mid) res=query(xds[rt].lson,l,mid,ll,rr);
if(rr>mid) res+=query(xds[rt].rson,mid+1,r,ll,rr);
return res;
}
int lowbit(int x){return x&-x;}
void szmotify(int id,int x,int val){for(int i=id;i<=n;i+=lowbit(i)) motify(root[i],1,n,x,val);}
int szquery(int id,int x,int type)
{
int res=0;
if(type==1)
{
// cout<<res<<'\n';
for(int i=id;i;i-=lowbit(i))
{
// cout<<res<<'\n';
res+=query(root[i],1,n,x+1,n);
}
}
if(type==2)
{
for(int i=n;i;i-=lowbit(i)) res+=query(root[i],1,n,1,x-1);
for(int i=id-1;i;i-=lowbit(i)) res-= query(root[i],1,n,1,x-1);
}
return res;
}
void solve()
{
cin>>n>>q;
int res=0;
map<int,int>s;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
s[x]=i;
res+=szquery(s[x]-1,x,1);
szmotify(i,x,1);
}
while(q--)
{
cout<<res<<"\n";
int x;
cin>>x;
int a=0,b=0;
if(x<n) a+= szquery(s[x]-1,x,1);//前面大于x的个数
if(x>1) b+= szquery(s[x]+1,x,2);//小于x的个数
res-=(a+b);
szmotify(s[x],x,-1);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T=1;
while(T--){solve();}
return 0;
}