“21 天好习惯”第一期-9

E. Optimal Insertion

考虑是把 b {b} b序列中的元素插入到 a {a} a序列中, b {b} b序列插入的相对位置一定是值小的在前面。

b i < b j , i < j {b_i<b_j,i<j} bi<bj,i<j,当前得到 a n s {ans} ans对逆序数, b i 、 b j {b_i、b_j} bibj之间值在 b i ∼ b j {b_i\sim b_j} bibj之间的元素有 x {x} x个,值大于 b j {b_j} bj的元素有 y {y} y个,值小于 b i {b_i} bi的元素有 z {z} z个,那么交换 b i {b_i} bi b j {b_j} bj插入的相对位置后当前的逆序数个数为 a n s + x + 1 {ans+x+1} ans+x+1个。故得证。

枚举 b i {b_i} bi,对 a {a} a序列,小于 b i {b_i} bi的位置设为0,大于 b i {b_i} bi的位置设为1,(等于 b i b_i bi的情况稍后考虑),那么 b i {b_i} bi插在 a j {a_j} aj之前构成的逆序数的对数等于 [ 1 , j − 1 ] {[1,j-1]} [1,j1]中1的个数加上 [ j , n ] {[j,n]} [j,n]中0的个数( j = 1 {j=1} j=1的时候等于 [ 1 , n ] {[1,n]} [1,n]中0的个数, j = n + 1 {j=n+1} j=n+1的时候等于 [ 1 , n ] {[1,n]} [1,n]中1的个数)。

考虑 b 0 = 0 {b_0=0} b0=0,所有的位置都是 1 {1} 1,那么 b 0 {b_0} b0插在 a j {a_j} aj之前构成的逆序数的对数等于 j − 1 {j-1} j1

插入 b 1 > b 0 {b_1>b_0} b1>b0时,部分位置由 1 {1} 1变为 0 {0} 0 p {p} p位置的 1 {1} 1变为0,导致 [ 1 , p − 1 ] {[1,p-1]} [1,p1]逆序对数+1, [ p , n + 1 ] {[p,n+1]} [p,n+1]逆序对数-1。

对于等于 b i b_i bi的位置,和 b i {b_i} bi不构成逆序数,但对 b j > b i {b_j>b_i} bj>bi构成逆序数。

先离散化

code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e6+7,mod=998244353 ;
int t[maxn<<2],n,m,lazy[maxn<<2];
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline void build(int l,int r,int rt) {
	lazy[rt]=0;
	if(l==r) {
		t[rt]=l-1;
		return;
	}
	int mid=(l+r)/2;
	build(lson);
	build(rson);
	t[rt]=min(t[rt<<1],t[rt<<1|1]);
}//0插在pos之前 
void pushdown(int rt) {
	if(lazy[rt]) {
		t[rt<<1]+=lazy[rt];
		t[rt<<1|1]+=lazy[rt];
		lazy[rt<<1]+=lazy[rt];
		lazy[rt<<1|1]+=lazy[rt];
		lazy[rt]=0;
	}
}
inline void update(int x,int y,int val,int l,int r,int rt) {
	if(x>y) return;
	if(x<=l&&r<=y) {
		t[rt]+=val;
		lazy[rt]+=val;
		return;
	}
	pushdown(rt);
	int mid=(l+r)/2;
	if(y<=mid) update(x,y,val,lson);
	else if(x>mid) update(x,y,val,rson);
	else {
		update(x,y,val,lson);
		update(x,y,val,rson);
	}
	t[rt]=min(t[rt<<1],t[rt<<1|1]);
}
int tr[maxn];
inline void add(int x) {
	while(x<=n+m+1) {
		tr[x]+=1;
		x+=(x&-x);
	}
}
inline int qry(int x) {
	int res(0);
	while(x) {
		res+=tr[x];
		x-=(x&-x);
	}
	return res;
}
inline void solve() {
	int cnt(0),pos(1);
	ll res(0);
	cin>>n>>m;
	vector<int>a(n+1),b(m+1),A(n+m+1);
	vector<pair<int,int> >p(n+1);
	map<int,int>mp;
	for(int i=1;i<=n+m+1;++i) tr[i]=0;
	for(int i=1;i<=n;++i) {
		cin>>a[i],A[i]=a[i];
	}
	for(int i=1;i<=m;++i) cin>>b[i],A[i+n]=b[i];
	sort(A.begin()+1,A.end());
	sort(b.begin()+1,b.end());
	int nm=unique(A.begin()+1,A.end())-A.begin();
	for(int i=1;i<=n;++i) a[i]=lower_bound(A.begin()+1,A.begin()+nm,a[i])-A.begin();
	for(int i=1;i<=m;++i) b[i]=lower_bound(A.begin()+1,A.begin()+nm,b[i])-A.begin();
	for(int i=n;i;--i) {
		res+=qry(a[i]-1),add(a[i]);
		p[i].first=a[i],p[i].second=i;
	}
	sort(p.begin()+1,p.end());
	build(1,n+1,1);
	ll ans(0);
	for(int i=1;i<=m;++i) {
		while(pos<=n&&p[pos].first<b[i]) {
			update(1,p[pos].second,1,1,n+1,1);
			update(p[pos].second+1,n+1,-1,1,n+1,1);
			++pos;
		} 
		if(b[i]!=b[i-1]) for(int j=pos;j<=n&&p[j].first==b[i];++j)
			update(p[j].second+1,n+1,-1,1,n+1,1);
		ans+=t[1];
		if(b[i]!=b[i+1]||i==m) while(pos<=n&&p[pos].first==b[i]) {
			update(1,p[pos].second,1,1,n+1,1);
			++pos;
		}
	}
	cout<<ans+res<<'\n';
}
int main() {
	cin.sync_with_stdio(false), cin.tie(nullptr),cout.tie(nullptr);
	int _=1;
	cin>>_;
	while(_--) solve();
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值