CF1601C题解

赛时一小时,赛后十分钟。

题意:给定一个序列 a 和一个集合 b,问将 b 中所有元素插入 a 后逆序对最少是多少。

观察样例解释,发现 b 已经被排序过了,于是就猜想一个结论:

设排序后 bixi1xi 之间被插入,那么对于 i<j 时一定有 xixj

证明:邻项交换,假如交换两个相邻元素,相当于令 bi 变大,bj 变小,这样一来 xi 右边的元素对 bi 的贡献就变大了,xj 左边的元素同理。

于是将 b 排序后依次插入 a。考虑在线地插入 b。那么对于 a 上的每一个位置得维护当前左边比该元素大的个数和当前右边比该元素小的个数。

由于已经将 b 排序了,所以可以考虑维护 si 表示 [1,i) 比当前的 b 大的元素个数与 [i,n] 不大于当前 b 的元素个数之和。将 a 也排序即可。

这样就可以动态地统计答案了。

#include<algorithm>
#include<cstdio>
const int M=1e6+5;
int T,n,m,t,a[M],b[M],id[M],mi[M*21];int len,lsh[M<<1];int tim[M*21],tag[M*21];
inline void upd(const int&u,const int&id){
	tim[u]^t&&(mi[u]=id-1,tim[u]=t,tag[u]=0);
}
inline void update(const int&u){
	mi[u]=mi[u<<1|mi[u<<1]>mi[u<<1|1]];
}
inline void pushdown(const int&u,const int&L,const int&R){
	if(!tag[u])return;upd(u<<1,L);upd(u<<1|1,(L+R>>1)+1);
	mi[u<<1]+=tag[u];mi[u<<1|1]+=tag[u];tag[u<<1]+=tag[u];tag[u<<1|1]+=tag[u];tag[u]=0;
}
void Modify(const int&u,const int&l,const int&r,const int&val,const int&L=1,const int&R=n+1){
	if(upd(u,L),l>R||L>r)return;if(l<=L&&R<=r)return mi[u]+=val,tag[u]+=val,void();pushdown(u,L,R);
	int mid=L+R>>1;Modify(u<<1,l,r,val,L,mid);Modify(u<<1|1,l,r,val,mid+1,R);update(u);
}
namespace BIT{
	int t,tim[M<<1],sum[M<<1];
	inline void Add(int x){
		for(;x<=len;x+=x&-x)tim[x]^t&&(sum[x]=0,tim[x]=t),++sum[x];
	}
	inline int Query(int x){
		int ans(0);
		for(;x>=1;x-=x&-x)tim[x]^t&&(sum[x]=0,tim[x]=t),ans+=sum[x];
		return ans;
	}
}
signed main(){
	int i,x,y;long long sum;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);++t;++BIT::t;sum=len=0;x=y=1;
		for(i=1;i<=n;++i)scanf("%d",a+i),lsh[++len]=a[id[i]=i];
		for(i=1;i<=m;++i)scanf("%d",b+i),lsh[++len]=b[i];std::sort(b+1,b+m+1);
		std::sort(id+1,id+n+1,[](const int&x,const int&y){return a[x]<a[y];});
		std::sort(lsh+1,lsh+len+1);len=std::unique(lsh+1,lsh+len+1)-lsh-1;
		for(i=1;i<=n;++i)a[i]=std::lower_bound(lsh+1,lsh+len+1,a[i])-lsh;
		for(i=1;i<=m;++i)b[i]=std::lower_bound(lsh+1,lsh+len+1,b[i])-lsh;
		for(i=n;i>=1;--i)sum+=BIT::Query(a[i]-1),BIT::Add(a[i]);mi[1]=0;
		for(i=1;i<=m;++i){
			while(a[id[x]]<b[i]&&x^n+1)Modify(1,1,id[x++],1);
			while(a[id[y]]<=b[i]&&y^n+1)Modify(1,id[y++]+1,n+1,-1);sum+=mi[1];
		}
		printf("%lld\n",sum);
	}
}

本文作者:Prean

本文链接:https://www.cnblogs.com/lmpp/p/15788236.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Prean  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
var canShowAdsense=function(){return !!0};
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起