【序列莫队+树状数组】BZOJ3289-Mato的文件管理
2016-07-26 21:07
453 查看
【题目大意】
一共有n份,每份有一个大小和一个编号。Mato每天随机选一个区间[l,r],拷贝出来(即对原序列不影响),给它们排序,并且每次只能交换相邻两份文件。问每天最少交换几次?
【思路】
显然,每天最少交换次数=[l,r]逆序对的个数。离散化后,用莫队离线查询,用树状数组来维护当前的区间。
假设我们已经知道[l,r]的逆序对的个数,怎样才能求出[l-1,r],[l+1,r],[l,r-1]和l[r+1]呢?
随便考虑序列3,5,2,4,7,6,8,已知[2,4]逆序对的个数为2对。[l-1,r]逆序对的个数有3对,即加上比3小的个数;[l+1,r]逆序对的个数有0对,即减去比5小的个数;[l,r-1]有1对,即减去比4大的数的个数;[l,r+1]有2对,即加上比7大的数的个数,由此可以得出结论:
@AutSky_JadeK
①在一列数的后面添加一个数,逆序对数会增加 数列中比它大的数的个数。
②在一列数的后面删除一个数,逆序对数会减少 数列中比它大的数的个数。
③在一列数的前面添加一个数,逆序对数会增加 数列中比它小的数的个数。
④在一列数的前面删除一个数,逆序对数会减少 数列中比它小的数的个数。
时间复杂度为O(n^1.5*log(n))
一共有n份,每份有一个大小和一个编号。Mato每天随机选一个区间[l,r],拷贝出来(即对原序列不影响),给它们排序,并且每次只能交换相邻两份文件。问每天最少交换几次?
【思路】
显然,每天最少交换次数=[l,r]逆序对的个数。离散化后,用莫队离线查询,用树状数组来维护当前的区间。
假设我们已经知道[l,r]的逆序对的个数,怎样才能求出[l-1,r],[l+1,r],[l,r-1]和l[r+1]呢?
随便考虑序列3,5,2,4,7,6,8,已知[2,4]逆序对的个数为2对。[l-1,r]逆序对的个数有3对,即加上比3小的个数;[l+1,r]逆序对的个数有0对,即减去比5小的个数;[l,r-1]有1对,即减去比4大的数的个数;[l,r+1]有2对,即加上比7大的数的个数,由此可以得出结论:
@AutSky_JadeK
①在一列数的后面添加一个数,逆序对数会增加 数列中比它大的数的个数。
②在一列数的后面删除一个数,逆序对数会减少 数列中比它大的数的个数。
③在一列数的前面添加一个数,逆序对数会增加 数列中比它小的数的个数。
④在一列数的前面删除一个数,逆序对数会减少 数列中比它小的数的个数。
时间复杂度为O(n^1.5*log(n))
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; struct node { int num,pos; bool operator < (const node &x) const {return num<x.num;} }; struct queries { int l,r,pos,id,ans; }; const int MAXN=50000+50; int n,m,size[MAXN],e[MAXN]; node tmpsize[MAXN]; queries q[MAXN]; bool cmp(queries a,queries b) { return (a.pos==b.pos)?a.r<b.r:a.pos<b.pos; } bool cmpid(queries a,queries b) { return a.id<b.id; } int lowbit(int x) { return (x&(-x)); } int sum(int p) { int ret=0; while (p>0) { ret+=e[p]; p-=lowbit(p); } return ret; } void modify(int p,int x) { while (p<=n) { e[p]+=x; p+=lowbit(p); } } void init() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&tmpsize[i].num); tmpsize[i].pos=i; } sort(tmpsize+1,tmpsize+n+1); for (int i=1,j=0;i<=n;i++) { if (i==1 || tmpsize[i].num!=tmpsize[i-1].num) j++; size[tmpsize[i].pos]=j; } scanf("%d",&m); int block=int(sqrt(n)); for (int i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; q[i].pos=(q[i].l-1)/block+1; } sort(q+1,q+m+1,cmp); } void query() { memset(e,0,sizeof(e)); int l=1,r=0,ans=0; for (int i=1;i<=m;i++) { while (l<q[i].l) modify(size[l],-1),ans-=sum(size[l]-1),l++; while (l>q[i].l) l--,modify(size[l],1),ans+=sum(size[l]-1); while (r>q[i].r) modify(size[r],-1),ans-=r-l-sum(size[r]),r--; while (r<q[i].r) r++,modify(size[r],1),ans+=r-l+1-sum(size[r]); q[i].ans=ans; } sort(q+1,q+m+1,cmpid); for (int i=1;i<=m;i++) printf("%d\n",q[i].ans); } int main() { init(); query(); return 0; }
相关文章推荐
- Android TV gridview 的按键事件响应巧变 && 事件分发机制
- ajax知识点总结
- 手把手教你连接mysql数据库
- Servlet基本应用
- Caffe 环境搭建中应注意的问题
- ART、JIT、AOT、Dalvik之间有什么关系?
- 块存储、文件存储、对象存储差别
- 查看ubuntu版本
- Redis下载后无redis-server.exe
- Can you solve this equation?
- 网易实习生笔试编程题 比较重量
- C/C++定义全局变量
- 数组排序-选择排序
- KNN算法源码解析
- Python 第十课,面向对象补足,异常处理
- 激活
- Ubuntu14.04下手动建立快捷方式
- 【杭电2141】Can you find it?
- hdu1520 Anniversary party 【树形dp】
- PHP进阶(五)——文件操作