前言
为什么能用整体二分呢?点我。
正文
这道题明显我们可以算每次删除会多少个逆序对 ( i , j ) (i,j) (i,j)。
我们定义 d i e die die 为该数字删除了多久(如果没有被删除自然是 0,如果第一个就是他被删除了就为 M M M)。
那么在 ( i , j ) (i,j) (i,j) 中如果有任意一个数值的 d i e die die 大于另一个数值的 d i e die die 那么那个数的删除就对总逆序对有 1 的贡献(注意:选择的数字既可以是下标为 i i i 的数字也可以是下标为 j j j 的数字)。
那么我们就可以得出关于每一个被删除数字对总逆序对有贡献的前提 i < j i<j i<j、 a i > a j a_i>a_j ai>aj、 d i e i > d i e j die_i>die_j diei>diej 或 i > j i>j i>j、 a i < a j a_i<a_j ai<aj、 d i e i > d i e j die_i>die_j diei>diej。(输入的数组为 a i a_i ai)
这不就是三维偏序(三维偏序的整体二分写法:点我)吗?
所以我们只需要用整体二分分别以上面的前提条件扫两遍即可。
代码
#include<bits/stdc++.h>
#define int long long
#define N 212345
#define lowbit(x) ((x)&(-x))
using namespace std ;
int n , m , ans[N] , tr[N] , cnt=0 , before=0 ;
struct user8341006{
int a , b , c , i ; // a为下标 b为值 c为删除的时间
}f[N];
void change(int x,int k){
while(x<=n){
tr[x] += k ;
x += lowbit(x) ;
}
}
int ask(int x){
int sum=0 ;
while(x){
sum += tr[x] ;
x -= lowbit(x) ;
}
return sum ;
}
bool cmp1(user8341006 a,user8341006 b){return a.b>b.b;}
bool cmp2(user8341006 a,user8341006 b){return a.b<b.b;}
bool cmp3(user8341006 a,user8341006 b){return a.b>b.b;}
bool cmp4(user8341006 a,user8341006 b){return a.a>b.a;}
struct node{
int x1 , x2 , opt , i ;
}a[N],q1[N],q2[N];
void solve(int l,int r,int L,int R){
if(L>R) return ;
if(l>=r) return ;
int mid=(l+r)>>1, tot1=0 , tot2=0 ;
for(int i=L;i<=R;i++){
if(a[i].opt==1){
if(mid>=a[i].x1) change(a[i].x2,1) , q1[++tot1] = a[i] ;
else q2[++tot2] = a[i] ;
}else if(a[i].opt==2){
if(mid>=a[i].x1){
q1[++tot1] = a[i] ;
}else{
ans[a[i].i] += ask(a[i].x2-1) ;
q2[++tot2] = a[i] ;
}
}
}
for(int i=1;i<=tot1;i++){
a[i+L-1] = q1[i] ;
if(q1[i].opt==1) change(q1[i].x2,-1) ;
}
for(int i=1;i<=tot2;i++) a[i+L+tot1-1] = q2[i] ;
solve(l,mid,L,L+tot1-1) ;
solve(mid+1,r,L+tot1,R) ;
}
signed main(){
cin >> n >> m ;
for(int i=1;i<=n;i++)
scanf("%lld",&f[i].b) , f[i].a = i , f[i].c = 0 ;
sort(f+1,f+1+n,cmp1) ;
for(int i=1;i<=n;i++){
before += ask(f[i].a) ;
change(f[i].a,1) ;
}
memset(tr,0,sizeof tr) ;
sort(f+1,f+1+n,cmp2) ;
for(int i=1;i<=m;i++){
int temp ;
scanf("%lld",&temp) ;
f[temp].c = m-i+1 ;
f[temp].i = i ;
}
sort(f+1,f+1+n,cmp3) ;
for(int i=1;i<=n;i++){
a[++cnt].x1 = f[i].c ;
a[cnt].x2 = f[i].a , a[cnt].opt = 1 ;
a[++cnt].x1 = f[i].c ;
a[cnt].i = f[i].i , a[cnt].x2 = f[i].a , a[cnt].opt = 2 ;
}
solve(-1,n+n,1,cnt) ;
sort(f+1,f+1+n,cmp4) ;
cnt=0 ;
for(int i=1;i<=n;i++){
a[++cnt].x1 = f[i].c ;
a[cnt].x2 = f[i].b , a[cnt].opt = 1 ;
a[++cnt].x1 = f[i].c ;
a[cnt].i = f[i].i , a[cnt].x2 = f[i].b , a[cnt].opt = 2 ;
}
solve(-1,n+n,1,cnt) ;
for(int i=1;i<=m;i++) printf("%lld\n",before) , before -= ans[i] ;
return 0 ;
}
/*
5 5
3 4 2 1 5
1 2 5 3 4
f[i].a < f[j].a
f[i].b > f[i].b
f[i].c > f[i].c
f[i].a > f[j].a
f[i].b < f[j].b
f[i].c > f[j].c 死了多长时间
求有多少(i,j)会受到i的影响
*/