CF1601C题解
赛时一小时,赛后十分钟。
题意:给定一个序列 \(a\) 和一个集合 \(b\),问将 \(b\) 中所有元素插入 \(a\) 后逆序对最少是多少。
观察样例解释,发现 \(b\) 已经被排序过了,于是就猜想一个结论:
设排序后 \(b_i\) 在 \(x_i-1\) 和 \(x_i\) 之间被插入,那么对于 \(i<j\) 时一定有 \(x_i \leq x_j\)。
证明:邻项交换,假如交换两个相邻元素,相当于令 \(b_i\) 变大,\(b_j\) 变小,这样一来 \(x_i\) 右边的元素对 \(b_i\) 的贡献就变大了,\(x_j\) 左边的元素同理。
于是将 \(b\) 排序后依次插入 \(a\)。考虑在线地插入 \(b\)。那么对于 \(a\) 上的每一个位置得维护当前左边比该元素大的个数和当前右边比该元素小的个数。
由于已经将 \(b\) 排序了,所以可以考虑维护 \(s_i\) 表示 \([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);
}
}