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

题意:给定一个序列 \(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);
}
}

最新文章

  1. Ajax表单序列化后的数据格式转成Json发送给后台
  2. Node.js Web 开发框架大全《中间件篇》
  3. 在windows下新建maven项目
  4. Bootstrap 3 How-To #2 标题,链接与按钮
  5. 【转】linux代码段,数据段,BSS段, 堆,栈
  6. Java简单算法--求100以内素数
  7. iOS利用响应链机制点击tableview空白处关闭键盘-可以作为参考
  8. wiki oi 3115高精度练习之减法
  9. c语言基础编程
  10. iOS App签名的原理
  11. 求n的阶乘
  12. 【Android 应用开发】BluetoothServerSocket详解
  13. 201771010126王燕《面向对象程序设计(Java)》第三周学习总结
  14. 《JavaScript Dom 编程艺术》读书笔记-第5章
  15. 《大话设计模式》c++实现 之策略模式
  16. SpringLog4j日志体系实现方式
  17. 启动node程序报错:event.js:183 throw er; // unhandled &#39;error&#39; event
  18. day 29 socketsetserver 模块
  19. CSS-div高度100%设置问题
  20. Python 网络编程和Socket

热门文章

  1. Ubuntu 18.04 修改默认源为国内源
  2. HOOK API(三) —— HOOK 所有程序的 MessageBox
  3. Ubuntu下Java JDK安装
  4. js null和{}区别
  5. Java高质量博文链接集合
  6. Pandas之groupby分组
  7. Solution -「LOCAL」过河
  8. suse 12 配置ip,dns,网关,hostname,ssh以及关闭防火墙
  9. 利用iptables做网络转发
  10. Python数据分析 | Numpy与1维数组操作