题解::``Dynamic‘‘ Inversion

前言

为什么能用整体二分呢?点我

正文

这道题明显我们可以算每次删除会多少个逆序对 ( 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 412345
#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 ;
}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(){
	while(cin >> n >> m){
		memset(ans,0,sizeof ans) ;
		before = 0 ;
		cnt=0 ;
		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的影响
*/
  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值