【BZOJ3289】【莫队分块+树状数组求逆序对】Mato的文件管理
2015-10-29 10:42
453 查看
3289: Mato的文件管理
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1123 Solved: 495
[Submit][Status][Discuss]
Description
Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号。为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问。Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料。Mato有一个习惯,他总是从文件大小从小到大看资料。他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。排序程序可以在1单位时间内交换2个相邻的文件(因为加密需要,不能随机访问)。Mato想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?Input
第一行一个正整数n,表示Mato的资料份数。第二行由空格隔开的n个正整数,第i个表示编号为i的资料的大小。
第三行一个正整数q,表示Mato会看几天资料。
之后q行每行两个正整数l、r,表示Mato这天看[l,r]区间的文件。
Output
q行,每行一个正整数,表示Mato这天需要交换的次数。Sample Input
41 4 2 3
2
1 2
2 4
Sample Output
02
HINT
Hintn,q <= 50000
样例解释:第一天,Mato不需要交换
第二天,Mato可以把2号交换2次移到最后。
Source
By taorunz#include<stdio.h> #include<string.h> #include<ctype.h> #include<math.h> #include<iostream> #include<string> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T> inline void gmax(T &a,T b){if(b>a)a=b;} template <class T> inline void gmin(T &a,T b){if(b<a)a=b;} const int N=5e4+10,M=0,Z=1e9+7,ms63=1061109567; int casenum,casei; int v ,w ; map<int,int>mop; map<int,int>::iterator it; int n,m; struct A { int l,r,o,id; bool operator < (const A& b)const { return id!=b.id?id<b.id:r<b.r; } }a ; int b ,top,l,r; void add(int x,int v) { for(;x<=top;x+=x&-x)b[x]+=v; } int cnt(int x) { int tmp=0; for(;x;x-=x&-x)tmp+=b[x]; return tmp; } int Lins(int x)//每次在最前添加一个数,比这个数小的数都会与其形成一个逆序对 { add(x,1); return cnt(x-1); } int Rins(int x)//每次在最后添加一个数,比这个数大的数都会与其形成一个逆序对 { add(x,1); return r-l+1-cnt(x); } int Ldel(int x)//每次在最前移除一个数,比这个数小的数都会与其减少一个逆序对 { add(x,-1); return cnt(x-1); } int Rdel(int x)//每次在最后移除一个数,比这个数大的数都会与其减少一个逆序对 { add(x,-1); return r-l+1-cnt(x); } int ans ; void reorder()//采取两种方式做离散化处理,效率差别并不大 { mop.clear(); for(int i=1;i<=n;i++)read(v[i]),mop[v[i]]=0; for(top=0,it=mop.begin();it!=mop.end();it++)it->second=++top; for(int i=1;i<=n;i++)v[i]=mop[v[i]]; /*for(int i=1;i<=n;i++)read(v[i]),w[i]=v[i]; sort(w+1,w+n+1); for(int i=1;i<=n;i++)v[i]=lower_bound(w+1,w+n+1,v[i])-w; top=n;*/ } int main() { //fre(); while(read(n)) { reorder(); int len=sqrt(n); read(m); for(int i=1;i<=m;i++) { read(a[i].l);read(a[i].r); a[i].o=i; a[i].id=a[i].l/len; } sort(a+1,a+m+1); l=a[1].l; r=l-1; int ANS=0; MS(b,0); for(int i=1;i<=m;i++) { while(l>a[i].l)ANS+=Lins(v[--l]);//左界左移 while(r<a[i].r)ANS+=Rins(v[++r]);//右界右移 while(l<a[i].l)ANS-=Ldel(v[l++]);//左界右移 while(r>a[i].r)ANS-=Rdel(v[r--]);//右界左移 ans[a[i].o]=ANS; } for(int i=1;i<=m;i++)printf("%d\n",ans[i]); } return 0; } /* 【trick&&吐槽】 1,莫队指针移动,对于答案的贡献的±号千万不能写反了 2,排序规则不要写错QwQ 3,对于while(l<a[i].l)ANS-=Ldel(v[l++]);这样的代码, 传进的参数是Ldel(v[l+1]),但是在过程内部,l已经变成了l+1。 也就是说,l++发生在过程执行之前,而并非是执行完这个过程之后。 【题意】 有n(5e4)个数,有m(5e4)个区间询问。 对于每个询问[l,r],我们想要知道在[l,r]范围内有多少个逆序对。 【类型】 莫队分块+树状数组 【分析】 1,对于逆序对的询问,可以把权值按照大小做离散化,然后—— 每次在最后添加一个数,比这个数大的数都会与其形成一个逆序对 每次在最后移除一个数,比这个数大的数都会与其形成一个逆序对 每次在最前添加一个数,比这个数小的数都会与其减少一个逆序对 每次在最前移除一个数,比这个数小的数都会与其减少一个逆序对 2,这题可以把区间询问离线处理,于是可以通过莫队实现 【时间复杂度&&优化】 O(n^1.5*log(n)) cnt(top)这样的命令可以省略为——直接求出当前的数字总数,这个会加快一定的速度。 【数据】 Sample Input 4 1 4 2 3 2 1 2 2 4 Sample Output 0 2 */
相关文章推荐
- JS金额小写转大写
- activemq-cpp 例子编译
- MFC下的键盘响应代码
- android EditText获取光标位置并插入字符删除字符
- UML
- [转]一个比较实用的VS C++版本号自增的实现方式
- Activiti系列:如何把Activiti工程转换为maven工程以解决依赖项找不到的问题
- [No000037]操作系统Operating Systems操作系统历史与硬件概况History of OS & Summaries!
- python模块
- mybatis-generator自动生成dao,mapping,model
- Java NIO.2 —— 文件或目录删除操作
- Java反射机制
- C++常见几种输出方法评测(int && long long)
- CXF开发webservice的小demo以及需要的jar包
- 修改对话框左上角的标题用SetWindowText(L“对话框的标题")即可
- oracle数据库错误ORA-00257:archiver error.
- [原创] 分享一些linux教程
- 微信获取二维码开发
- SWIFT——枚举数组元素的方法
- linux下sar命令的用法