【cdq分治】[HYSBZ/BZOJ3295]动态逆序对
2016-02-19 10:30
405 查看
题目
看看这篇博客写的时间,BZOJ已经挂了,我就不粘BZOJ链接了。Description
对于序列A,它的逆序对数定义为满足i < j,且Ai > Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
Hint
样例解释
(1,5,3,4,2)>>(1,3,4,2)>>(3,4,2)>>(3,2)>>(3)。
数据范围
编号 1-2 3-4 5-6 7-8 9-10
n <=1000 <=30000 <=50000 <=60000 <=100000
m <=100 <=10000 <=20000 <=40000 <=50000
分析
这道题
我们令y表示当前数字,t表示y被加入(先被删除的后加入)的时间,x表现y在原串中的位置,这样一个数字就变成了一个三元组(t,x,y)。不难发现,当一个数字(t0,x0,y0)对最终的逆序对数作出的贡献为存在的三元组(t,x,y)使得(t<t0,(x<x0)xor(y<y0)==1)(t < t0,(x < x0)xor(y < y0)==1)的数量。
这样,我们就可以用cdq分治做这道题。
如果你已经会cdq请直接看代码。
如何用cdq分治做这道题
This part was powered by azui即t<t0,x<x0,y>y0ty0或者t<t0,x>x0,y<y0。tx0,y
我们先考虑满足条件一:t<t0,x<x0,y>y0ty0的点。
在外面按x排序后,还剩下t,y两个参数。我们可以对t进行划分排序,使得t,x满足
。
然后就可以求出对于每一个右边的三元组(t0,x0,y0),有多少个点满足t<t0,x<x0t(类似于归并排序),然后用树状数组维护这些三元组中有哪些y>y0y>y0。
条件二类似。
然后递归处理左右两边。
感谢azui大神,你们也可以去看他自己的博客。
代码
[code]#include<cstdio> #include<algorithm> #define MAXN 100000 using namespace std; struct node{ int t,x,y; node(){ } node(int tt,int xx,int yy){ t=tt,x=xx,y=yy; } }p[MAXN+10],tmp[MAXN+10]; int n,m,a[MAXN+10],t[MAXN+10],c[MAXN+10]; long long ans[MAXN+10]; void Read(int &x){ char c; while(c=getchar(),c!=EOF) if(c>='0'&&c<='9'){ x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; ungetc(c,stdin); return; } } inline int lowbit(int x){ return x&-x; } void update(int x,int d){ while(x<=n){ c[x]+=d; x+=lowbit(x); } } int get_sum(int x){ int ret=0; while(x){ ret+=c[x]; x-=lowbit(x); } return ret; } void read(){ Read(n),Read(m); int i,b,j=0; for(i=1;i<=n;i++) Read(a[i]); for(i=1;i<=m;i++){ Read(b); t[b]=i; } for(i=1;i<=n;i++) if(t[a[i]]) p[i]=node(n-t[a[i]]+1,i,a[i]); else p[i]=node(++j,i,a[i]); } void cdq(int l,int r){ if(l==r) return; int mid=(l+r)>>1,i,j,k; k=mid+1,j=l; for(i=l;i<=r;i++) if(p[i].t<=mid) tmp[j++]=p[i]; else tmp[k++]=p[i]; for(i=l;i<=r;i++) p[i]=tmp[i]; i=l; for(j=mid+1;j<=r;j++){ for(;i<=mid&&p[i].x<p[j].x;i++) update(p[i].y,1); ans[p[j].t]+=(i-l)-get_sum(p[j].y); } for(i--;i>=l;i--) update(p[i].y,-1); i=mid; for(j=r;j>mid;j--){ for(;i>=l&&p[i].x>p[j].x;i--) update(p[i].y,1); ans[p[j].t]+=get_sum(p[j].y); } for(i++;i<=mid;i++) update(p[i].y,-1); cdq(l,mid); cdq(mid+1,r); } void print(){ int i; for(i=2;i<=n;i++) ans[i]+=ans[i-1]; for(i=n;i>n-m;i--) printf("%I64d\n",ans[i]); } int main() { read(); cdq(1,n); print(); }
相关文章推荐
- 一个R语言使用函数处理的基本的案例
- android之wifi开发
- CentOS环境变量设置
- scrapy爬虫之Image Pipeline
- rotateAnimation 动画效果(转载)
- Android中自动连接到指定SSID的Wi-Fi
- template和templateUrl区别与联系
- IP工具类——IpAddress.java
- 【转】 制作Android Demo GIF:程序演示效果GIF图录制
- Delphi中获取文件大小
- mysql 查看 删除 日志操作总结(包括单独和主从mysql)
- 基于JavaScript实现弹出框效果
- listview实现上拉加载
- java 文件上传和下载处理
- STL 中的容器们
- PHP编译过程中常见错误信息的解决方法
- Linux下which、whereis、locate、find 命令的区别
- PHP职业规划
- Android wifi简要分析
- jQuery ajax请求方法汇总