[bzoj3289][树状数组][莫队算法]Mato的文件管理
2018-01-24 15:17
323 查看
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
4
1 4 2 3
2
1 2
2 4
Sample Output
0
2
HINT
Hint
n,q <= 50000
样例解释:第一天,Mato不需要交换
第二天,Mato可以把2号交换2次移到最后。
题解
看着就很像是求逆序对数
实际上也就是求逆序对,可以证明需要移动的次数=逆序对数
在不带修改的情况下,当然树状数组求逆序对最方便了。再观察一下范围,q<=50000,果断莫队
分四种情况讨论
队列最右边加数时,答案增加数为队列中比该数大的数的个数
队列最右边减数时,答案减少数为队列中比该数大的数的个数
队列最左边加数时,答案增加数为队列中比该数小的数的个数
队列最左边减数时,答案减少数为队列中比该数小的数的个数
分四种情况讨论即可
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
4
1 4 2 3
2
1 2
2 4
Sample Output
0
2
HINT
Hint
n,q <= 50000
样例解释:第一天,Mato不需要交换
第二天,Mato可以把2号交换2次移到最后。
题解
看着就很像是求逆序对数
实际上也就是求逆序对,可以证明需要移动的次数=逆序对数
在不带修改的情况下,当然树状数组求逆序对最方便了。再观察一下范围,q<=50000,果断莫队
分四种情况讨论
队列最右边加数时,答案增加数为队列中比该数大的数的个数
队列最右边减数时,答案减少数为队列中比该数大的数的个数
队列最左边加数时,答案增加数为队列中比该数小的数的个数
队列最左边减数时,答案减少数为队列中比该数小的数的个数
分四种情况讨论即可
hljs cpp">#include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int l,r,op; }a[51000];int block,n,m,pos[51000]; bool cmp(node n1,node n2) { return pos[n1.l]==pos[n2.l]?n1.r<n2.r:pos[n1.l]<pos[n2.l]; } struct sor { int y,p; }b[51000]; bool cmpd(sor n1,sor n2){return n1.y<n2.y;} int c[51000],s[51000]; int lowbit(int x){return x&-x;} void change(int x,int c) { while(x<=n) { s[x]+=c; x+=lowbit(x); } } int findsum(int x) { int ret=0; while(x>=1) { ret+=s[x]; x-=lowbit(x); } return ret; } int answer[51000]; int ans; int main() { scanf("%d",&n);block=sqrt(n); for(int i=1;i<=n;i++)scanf("%d",&c[i]),b[i].y=c[i],b[i].p=i; sort(b+1,b+1+n,cmpd); for(int i=1;i<=n;i++)c[b[i].p]=i; for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1; scanf("%d",&m); for(int i=1;i<=m;i++)scanf("%d%d",&a[i].l,&a[i].r),a[i].op=i; sort(a+1,a+1+m,cmp); ans=0; for(int i=a[1].l;i<=a[1].r;i++) { ans+=findsum(n)-findsum(c[i]); change(c[i],1); } answer[a[1].op]=ans; int l=a[1].l,r=a[1].r; for(int i=2;i<=m;i++) { while(l<a[i].l)change(c[l],-1),ans-=findsum(c[l]-1),l++; while(r>a[i].r)change(c[r],-1),ans-=findsum(n)-findsum(c[r]),r--; while(l>a[i].l)l--,ans+=findsum(c[l]-1),change(c[l],1); while(r<a[i].r)r++,ans+=findsum(n)-findsum(c[r]),change(c[r],1); answer[a[i].op]=ans; } for(int i=1;i<=m;i++)printf("%d\n",answer[i]); return 0; }
相关文章推荐
- BZOJ 3289 Mato的文件管理 莫队算法+树状数组
- 【BZOJ3289】Mato的文件管理 莫队算法+树状数组
- BZOJ 3289: Mato的文件管理[莫队算法 树状数组]
- bzoj3289 Mato的文件管理 莫队算法 树状数组
- 莫队+树状数组 题解【bzoj3289】Mato的文件管理
- 【BZOJ】3289: Mato的文件管理【区间逆序对,莫队套树状数组】
- 【BZOJ3289】【莫队分块+树状数组求逆序对】Mato的文件管理
- 【序列莫队+树状数组】BZOJ3289-Mato的文件管理
- Bzoj 3289: Mato的文件管理 莫队,树状数组,逆序对,离散化,分块
- [bzoj3289]Mato的文件管理_莫队_树状数组
- BZOJ 3289 Mato的文件管理 莫队算法+树状数组
- 【BZOJ3289】Mato的文件管理-莫队算法+树状数组
- 【BZOJ】3289: Mato的文件管理(莫队算法+树状数组)
- bzoj3289 Mato的文件管理 莫队算法
- BZOJ 3289 Mato的文件管理 莫队算法
- [BZOJ 3289] Mato的文件管理 · 莫队算法 & 树状数组
- bzoj 3289 Mato的文件管理(莫队算法+BIT)
- 【bzoj3289】Mato的文件管理 离散化+莫队算法+树状数组
- bzoj 3289: Mato的文件管理 (莫队算法 + 树状数组)
- BZOJ3289 Mato的文件管理(莫队算法+树状数组)